• 信号量 PV 操作


    信号量的类型定义

    一般来说,信号量(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();
    

    (完)

  • 相关阅读:
    高精度加法
    高精度计算(一)
    算法总结
    崛起之路
    2015浙江高考满分作文汇总(9篇)
    努力
    NOIP2015总结
    P3197 [HNOI2008]越狱[组合数学]
    【原创】SPFA判负环
    P1351 联合权值[鬼畜解法]
  • 原文地址:https://www.cnblogs.com/gu-castle/p/11436921.html
Copyright © 2020-2023  润新知