码迷,mamicode.com
首页 > 其他好文 > 详细

信号量 PV 操作

时间:2019-08-30 21:17:30      阅读:99      评论:0      收藏:0      [点我收藏+]

标签:情况   let   空间   定义   queue   大于   new   模拟   not   

信号量的类型定义

一般来说,信号量(semaphore)\(S\),表示资源数量减去需求数量。信号量的值仅能由 PV 操作来改变。

执行一次 P 操作意味着请求一个单位资源,因此 \(S\) 的值减 1;当 \(S < 0\) 时,需求数大于资源数,即已经没有可用资源,请求者必须等待。

执行一个 V 操作意味着释放一个单位资源,因此 \(S\) 的值加 1;若 \(S \ge 0\),此时资源数目能满足需求,所以可以唤醒一个在等待的请求者,让它获取资源。

\(S < 0\)\(|S|\) 即没有得到资源的请求者数目,也就是阻塞的线程数。

用互斥量和条件变量可以模拟信号量的行为:

use std::sync::Condvar;
use std::sync::Mutex;

pub struct Semaphore {
    sem: Mutex<i32>,
    con: Condvar,
}

impl Semaphore {
    pub fn new(sem: i32) -> Self {
        Self {
            sem: Mutex::new(sem),
            con: Condvar::new(),
        }
    }

    pub fn p(&self) {
        let mut sem = self.sem.lock().unwrap();

        *sem -= 1;
        if *sem < 0 {
            let _ = self.con.wait(sem).unwrap();
        }
    }

    pub fn v(&self) {
        let mut sem = self.sem.lock().unwrap();

        *sem += 1;
        if *sem <= 0 {
            self.con.notify_one();
        }
    }
}

互斥

当信号量的初始值取 1,任何第二个请求资源者会陷入饥饿。从而同一时刻只能有一个线程访问某个资源。

初始化一个信号量 mutexSemaphore::new(1),在使用临界资源之前调用 mutex.p(),使用完资源之后调用 mutex.v()。即实现了资源的互斥访问。

同步

设置起始资源为大于 1 的正数,则 PV 操作维护资源同步。

举例说明,要实现有 3 个缓冲区的、MPMS 的队列。抽象出两种资源:缓冲区空间(room)和队列中的数据(data)。队列为空的情况下,有 3 个 room 资源,没有 data 资源。

let room = Semaphore::new(3);
let data = Semaphore::new(0);
let queue = Queue::empty();

要往队列里添加元素,则需要一个 room 资源,操作完之后产生一个 data 资源。

room.p();
queue.push(x);
data.v();

要从队列头取出元素,则需要一个 data 资源,操作完之后产生一个 room 资源。

data.p();
let x = queue.pop();
room.v();

(完)

信号量 PV 操作

标签:情况   let   空间   定义   queue   大于   new   模拟   not   

原文地址:https://www.cnblogs.com/gu-castle/p/11436921.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!