【操作系统】第十章
来源:操作系统_清华大学(向勇、陈渝)
主要讨论:信号量、管程、条件互斥、经典同步问题
1.背景
并发问题:竞态条件
多线程并发存在大的问题。
同步:
多线程共享公共数据的协调协行
包括互斥与条件同步
互斥:在同一时间只有一个线程可以执行临界区
确保同步正确很难?
需要高层次的编程抽象(如:锁)
从底层硬件支持编译
2.信号量
这个信号量的概念来源自,我们临界代码访问资源时候,不一定互斥或者说上锁,因为我们可以是读操作,这样就要求对代码访问操作可以进行更多的控制。
一个整型int(sem),可进行两个原子操作:
P():信号量sem–,如果sem<0,等待,否则继续,类似lock_acquire
V() :信号量sem++,如果sem<=0,说明当前有等着的,唤醒挂在信号量上的进程,可以是一个,可以是多个
列车进入前是P操作,离开前是V操作。
3.信号量的使用
特征 :
信号量是整数,有符号,一般初始是>0的数,一旦小于0就不能继续,要挂在信号量上,其他进程做V操作才能唤醒,具体唤醒哪个取决于具体的算法,如常用FIFO先来先服务,较为公平;
信号量是被保护的变量,初始化完成后只能通过P() V()这两个原子操作改变值,P操作会阻塞,V不会阻塞。
我们假定信号量是“公平的”,没有线程被阻塞在P()操作仍然阻塞,如果V()被无限频繁调用(在同一个信号量)。
两种类型:
二进制信号量:约等于锁,取值0 or 1
general counting一般/技术信号量:任何非负值
信号量可以用在两个方面,互斥或者条件同步(调度约束—–一个线程等待另一个线程的事情发生)
条件同步:
条件同步正确性要求:
1.可以多个生产者访问Buffer写数据,但写的时候消费者不能有操作(互斥),
2.缓冲区空,消费者必须等待生产者,
3.缓冲区满,生产者必须等待消费者(调度/同步约束)。
每个约束用一个单独的信号量,设置三个:
二进制信号量互斥(1/0),一般信号量fullbuffers,一般信号量emptybuffer
4.信号量的实现
信号量的双用途:
1.互斥和条件同步
2.但等待条件是独立的互斥
读/开发代码比较困难:
程序员必须非常精通信号量
容易出错:
1.使用的信号量已经被另一个线程占用
2.忘记释放信号量
不能够处理死锁问题
5.管程
目的:分离互斥和条件同步的关注
管程(monitor):包含了一系列的共享变量,以及针对这些变量的操作的函数的组合/模块
管程:
一个锁lock:指定临界区
0或者多个条件变量:等待/通知信号量用于管理并发访问共享数据
一般方法:
1.收集在对象/模块中的相关共享数据
2.定义方法来访问共享数据
临界区和MONITOR比较:
1.两个同步互斥的机制,临界区和monitor,比起LOCK都可以解决更广泛的问题,但也都离不开底层的硬件支持。
2.同步互斥的不确定性强,调试困难。
6.经典同步问题
7.景点同步问题