操作系统知识点(七)——信号量

信号量

背景

信号量(semaphore)

  • 抽象数据类型

    • 一个整形(sem),两个原子操作

    • P():sem减1,如果sem<0,等待,否则继续

    • V():sem加1,如果sem<=0,唤醒一个等待的P

信号量使用

特性
  • 信号量是被保护的整数变量

    • 初始化完成后,只能通过P()和V()操作修改

    • 由操作系统保证,PV操作是原子操作

  • P()可能阻塞,V()不会阻塞

  • 通常假定信号量是”公平的“

    • 线程不会被无限期阻塞在P()操作

    • 假定信号量等待按先进先出排队

分类
  • 二进制信号量:可以是0或1

  • 一般/计数(资源)信号量:可取任何非负值

  • 两者等价:基于一个可以实现另一个

使用
  • 互斥访问:临界区的互斥访问控制

  • 条件同步:线程间的事件等待

生产者-消费者问题
  • 生成者->缓冲区->消费者

  • 有界缓冲区的生产者-消费者问题描述

    • 一个或多个生产者在生成数据后放在一个缓冲区里

    • 单个消费者从缓冲区取出数据处理

    • 任何时刻只能有一个生产者或消费者可访问缓冲区

  • 问题分析

    • 任何时刻只能有一个线程操作缓冲区(互斥访问)

    • 缓冲区空时,消费者必须等待生产者(条件同步)

    • 缓冲区满时,生产者必须等待消费者(条件同步)

  • 用信号量描述每个约束

    • 二进制信号量mutex

    • 资源信号量fullBuffers

    • 资源信号量emptyBuffers

class BoundedBuffer{
    mutex =new Semaphore(1);
    fullBuffers =new Semaphore(0);
    emptyBuffers =new Semaphore(n);
}
BoundedBuffer::Producter(c){
    emptyBuffers ->P();
    mutex ->P();
    ADD C TO THE BUFFER;
    mutex ->V();
    fullBuffers ->V();
}
BoundedBuffer::Consumer(c){
    fullBuffers ->P();
    mutex ->P();
    REMOVE C FROM BUFFER;
    mutex ->V();
    emptyBuffers ->V();
}

信号量实现

  • 实现
class Semaphore{
    int sem;
    WaitQueue q;
}
Semaphore: P(){
    sem--;
    if(sem<0){
        ADD THIS THREAD t TO q;
        block(q);
    }
}
Semaphore: V(){
    sem++;
    if(sem<=0){
        REMOVE a THREAD t FROM q;
        wakeup(t);
    }
}
  • 困难

    • 读/开发代码比较困难

    • 容易出错。使用的信号量已经被另一个线程占用;忘记释放信号量

    • 不能够处理死锁问题

管程(Moniter)

  • 管程是一种用于多线程互斥访问共享资源的程序结构

    • 采用面向对象方法,简化了线程间的同步控制

    • 任一时刻最多只有一个线程执行管程代码

    • 正在管程中的线程可临时放弃管程的互斥访问,等待事件出现时恢复

  • 使用

    • 在对象/模块中,收集相关共享数据

    • 定义访问共享数据的方法

  • 组成

    • 一个锁:控制管程代码的互斥访问

    • 0或者多个条件变量:管理共享数据的并发访问

  • 条件变量

    • 条件变量是管程内的等待机制

      • 进入管程的线程因资源被抢占而进入等待状态

      • 每个条件变量表示一种等待原因,对应一个等待队列

    • wait()操作

      • 将自己阻塞在等待队列中

      • 唤醒一个等待者或释放管程的互斥访问

    • signal()操作

      • 将等待队列中的一个线程唤醒

      • 如果等待队列为空,则等同空操作

  • 条件变量实现

class Condition{
    int numWaiting =0;
    WaitQueue q;
}
Condition::Wait(lock){
    numWaiting++;
    ADD this thread t to q;
    release(lock);
    schedule();
    require(lock);
}
Condition::Signal(){
    if(numWaiting >0){
        REMOVE a thread t from q;
        wakeup(t);
        numWaiting--;
    }
}
  • 管程解决生产者-消费者问题
class BoundedBuffer {
    …
    Lock lock;
    int count = 0;
    Condition notFull, notEmpty;
}
BoundedBuffer::Producter(c) {
    lock->Acquire();
    while (count == n)
        notFull.Wait(&lock);
    Add c to the buffer;
    count++;
    notEmpty.Signal();
    lock->Release();
}
BoundedBuffer::Consumer(c) {
    lock->Acquire();
    while (count == 0)    
      notEmpty.Wait(&lock);
    Remove c from buffer;
    count--;
    notFull.Signal();
    lock->Release();
}

经典同步问题

读者-写者问题
  • 共享数据的两类使用者

    • 读者:只读取数据,不修改

    • 写者:读取和修改数据

  • 读者-写者问题描述:对共享数据的读写

    • 读-读允许:同一时刻允许有多个读者同时读

    • 读-写互斥:没有写者时读者才能读,没有读者时写者才能写

    • 写-写互斥:没有其它写者时才能写

  • 信号量方法

class Writer(){
    P(WriteMutex);
    write;
    V(WriteMutex);
}
class Reader(){
    P(CountMutex);
    if(Rcount ==0)
        P(WriteMutex);
    ++Rcount;
    V(CountMutex);
    
    read;
    
    P(CountMutex);
    --Rcount;
    if(Rcount ==0)
        V(WriteMutex);
    V(CountMutex);
}
  • 管程方法
AR = 0;   // # of active readers
AW = 0;   // # of active writers
WR = 0;   // # of waiting readers
WW = 0;   // # of waiting writers
Lock lock;
Condition okToRead;
Condition okToWrite;

//读者
Private Database::StartRead() {
    lock.Acquire();
    while ((AW+WW) > 0) {
        WR++;
        okToRead.wait(&lock);
        WR--;
    }
    AR++;
    lock.Release();
}
Private Database::DoneRead() {
    lock.Acquire();
    AR--;
    if (AR ==0 && WW > 0) {
        okToWrite.signal();
    }
    lock.Release();
}
Public Database::Read() {
  //Wait until no writers;
  StartRead(); 
  read database;
  //check out – wake up waiting writers; 
  DoneRead(); 
}

//写者
Private Database::StartRead() {
    lock.Acquire();
    while ((AW+WW) > 0) {
        WR++;
        okToRead.wait(&lock);
        WR--;
    }
    AR++;
    lock.Release();
}
Private Database::DoneRead() {
    lock.Acquire();
    AR--;
    if (AR ==0 && WW > 0) {
        okToWrite.signal();
    }
    lock.Release();
}
Public Database::Read() {
  //Wait until no writers;
  StartRead(); 
  read database;
  //check out – wake up waiting writers; 
  DoneRead(); 
}
哲学家就餐问题
  • 问题描述

    • 5个哲学家围绕一张圆桌而坐

      • 桌子上放着5支叉子

      • 每两个哲学家之间放一支

    • 哲学家的动作包括思考和进餐

      • 进餐时需同时拿到左右两边的叉子

      • 思考时将两只叉子放回原处

更多精彩,关注“咋家”

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,978评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,954评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,623评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,324评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,390评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,741评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,892评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,655评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,104评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,569评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,254评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,834评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,725评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,950评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,260评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,446评论 2 348

推荐阅读更多精彩内容

  • 第10章:信号量与管程 信号量信号量使用互斥访问条件同步管程经典同步问题哲学家就餐问题读者-写者问题 10.1 信...
    liuzhangjie阅读 2,867评论 0 1
  • 18.1信号量 回顾 ■并发问题 多线程并发导致资源竞争 ■同步概念 协调多线程对共享数据的访问 任何时刻只能有一...
    龟龟51阅读 2,066评论 0 0
  • 线程同步(互斥锁与信号量的作用与区别) “信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别...
    胜浩_ae28阅读 4,943评论 0 2
  • 文/白鹭 每年,我总是特别喜欢九月,大家都说九月很符合我的气质,因为我是九月生的,微风凉,白露生,所以给自己取了笔...
    白鹭姑娘阅读 6,602评论 127 105
  • 21天E战到底第一天学习打卡,今天是第二次学习“认识Excel,突破理论”课程,时隔十天再次学习这个课程又有不同的...
    相信自己_d4c2阅读 215评论 0 3