18.1信号量
回顾
■并发问题
多线程并发导致资源竞争
■同步概念
协调多线程对共享数据的访问
任何时刻只能有一个线程执行临界区代码
■确保同步正确的方法
底层硬件支持
高层次的编程抽象
基本同步方法
信号量(semaphore)
■信号量是操作系统提供的一种协调共享资源访问的方法
软件同步是平等线程间的一种同步协商机制(线程是平等的)
OS是管理者,地位高于进程
用信号量表示系统资源的数量
■由Dijkstra在20世纪60年代提出
■早期的操作系统的主要同步机制
现在很少用(但还是非常重要在计算机科学研究)
■信号量是一种抽象数据类型
·由一个整形(sem)变量(共享资源数目)和两个原子操作组成
·P()(Prolaag(荷兰语尝试减少))
sem减1
如sem<0,进入等待,否则继续
·V()(Verhoog(荷兰语增加))
sem加1
如sem≤0,唤醒一个等待进程
信号量的特性
■信号量是被保护的整数变量
初始化完成后,只能通过P()和V()操作修改
由操作系统保证,PV操作是原子操作
■P()可能阻塞,V()不会阻塞
■通常假定信号量是“公平的”
线程不会被无限期阻塞在P()操作
假定信号量等待按先进先出排队
自旋锁能否实现先进先出?
自旋锁是需要占用CPU随时随地去查标志,有可能临界区的使用者退出的时候它刚改完标志,下一个进入者哪个线程去查,那它就能进去,如果说运气不好,正好是这个资源变成有效的时候,你去查的时候在你之前就有一个人已经查过了,就没有办法按照你等待的这个顺序来执行。
信号量的实现
18.2信号量的使用
精髓:
基本原理:两个或多个进程可以通过简单的信号进行合作,一个进程可以被迫在某一位置停止,直到它接收到一个特定的信号。任何复杂的合作需求都可以通过适当的信号结构得到满足。为了发信号,需要使用一个称做信号量的特殊变量。信号量分类
■可分为两种信号量
·二进制信号量:资源数目为0或1(有些系统称为互斥锁)
·资源信号量:资源数目为任何非负值
·两者等价
基于一个可以实现另一个
■信号量的使用
·互斥访问
■临界区的互斥访问控制
·条件同步
线程间的事件等待
用信号量实现临界区的互斥访问
用一个信号量来对应一个临界区,,通过mutex的值来确定该资源的情况,P()减一V()加一,但mutex为负值的时候表示使用该资源的线程有在排队的,这样来实现互斥访问
用信号量实现条件同步
也是通过condition这个值来控制的,有一个资源B只在使用,只用通过V()操作加一后,condition的值小于等于0就知道有另一个线程A在等他,然后唤醒A。
生产者-消费者问题
用信号量解决生产者-消费者问题
P、V操作的顺序有影响吗?
P、V颠倒会出现死锁,原因是先检查空、满再去申请互斥访问,如果申请了互斥访问,申请的进程已经占用了临界资源,其他进程不能读写,但是里面发现又是满的(写者)或者是空的(读者),写也写不下去,读也读不到,其他进程也不能申请这个临界区,所以形成死锁。
使用信号量的困难
■读/开发代码比较困难
程序员需要能运用信号量机制
■容易出错(忘了一个P/V操作或者操作顺序颠倒)
使用的信号量已经被另一个线程占用
忘记释放信号量
■不能够处理死锁问题
概念:信号量的关键之处是它们原子地执行。
SMP系统必须提供其他加锁技术(如自旋锁),以确保wait()和signal()(即P()V())可原子地执行。
18.3管程
基本同步方法
管程(Moniter)
■管程是一种用于多线程互斥访问共享资源的程序结构
采用面向对象方法,简化了线程间的同步控制
任一时刻最多只有一个线程执行管程代码
正在管程中的线程可临时放弃管程的互斥访问,等待事件出现时恢复
■管程的使用
在对象/模块中,收集相关共享数据
定义访问共享数据的方法
概念:管程类型提供了一组由程序员定义的、在管程内互斥的操作。
管程的组成
■一个锁(入口)
控制管程代码的互斥访问
■0或者多个条件变量
管理共享数据的并发访问
只允许一个线程在管程内部执行,如果说在这个内部,没有其它共享数据的话这时候呢就和临界区是完全一样的
管程特有:用来管理共享数据的并发访问需要这些共享资源的时候,与相应的条件变量对应的互斥操作才能执行
条件变量(Condition Variable)
■条件变量是管程内的等待机制
进入管程的线程因资源被占用而进入等待状态
每个条件变量表示一种等待原因,对应一个等待队列
条件变量仅有的操作wait和signal
■Wait()操作
将自己阻塞在等待队列中
被signal()唤醒一个等待者或释放管程的互斥访问
■Signal()操作
将等待队列中的一个线程唤醒
如果等待队列为空,则等同空操作
条件变量实现
用管程解决生产者-消费者问题
管程条件变量的释放处理方式
Hansen管程与Hoare管程
18.4哲学家就餐问题
方案1(信号量)
方案2(临界区)
方案3(保证每个哲学家拿起不同方向的叉)
18.5读者-写者问题
用信号量解决读者-写者问题
用管程解决读者-写者问题
精髓:
17、18小结
现代操作系统的核心是多道程序设计、多处理器和分布式处理器,这些方案的基础以及操作系统设计技术的基础是并发。当多个进程并发执行时,不论是在多处理器系统的情况下,还是单处理器多道程序系统中,都会产生冲突和合作的问题。
并发进程可以按多种方式进行交互。互相之间不知道对方的进程可能需要竞争使用资源,如处理器时间或对I/O设备的访问。进程间由于共享访问一个公共对象,如一块内存空间或一个文件,可能间接知道对方,这类交互中产生的重要问题是互斥和死锁。
互斥指的是,对一组并发进程,一次只有一个进程能够访问给定的资源或执行给定的功能。互斥技术可以用于解决诸如资源争用之类的冲突,还可以用于进程间的同步,使得它们可以合作。后一种情况的一个例子是生产者/消费者模型,一个进程向缓冲区中放数据,另一个或更多的进程从缓冲区中取数据。
支持互斥的第二种方法涉及使用专门的机器指令,这种方法减少了开销,但由于使用了忙等待,效率较低。
支持互斥的另一种方法是在操作系统中提供相应的功能,其中最常见的两种技术是信号量和消息机制。信号量用于在进程间发信号,并可以很容易地实施一个互斥协议。消息对实施互斥是很有用的,它还为进程间的通信提供了一种有效的方法。