10-并发控制:同步 (2)
可以用互斥锁来实现同步
在约定的状态上锁,然后同时解锁
(mutex库规定不能在一个线程获得锁,在另一个线程释放锁)
初始时都上锁,等待就是请求锁,
(信号量)P是取,V是放
拓展互斥锁,多个
happens-before
acquire-release
口袋和球,如果是一个球,那就是互斥锁
适用于可计数的资源
可以创建n个口袋
信号量用来实现生产者消费者
哲学家吃饭问题
刚开始的实现,简单使用信号量表示叉子,会出现死锁,即哲学家都拿起左手边的叉子或右手边的叉子,然后桌子上没有叉子,也没人放下
而用条件变量可以简单解决这个问题(哲学家会同时拿起或放下两只手的叉子)
信号量解决方法:
赶走桌子上的一个人,哲学家取到一个球才能上桌吃饭,吃完饭放回
但是问题更复杂,要求更多就很难了
给叉子编号也行,
条件变量是万能模板
用信号量实现条件变量
该例子是一个生产者一个消费者,缓冲区是1,如果缓冲区很大这个问题就会被忽视了,如果生产者和消费者数量增加,那么死锁概率也会增加
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| void wait(struct condvar *cv, mutex_t *mutex){ mutex_lock(&cv -> lock); cv -> nwait++; mutex_unlock(&cv -> lock);
mutex_unlock(mutex); P(&cv -> sleep); mutex_lock(mutex); }
|
问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Consumer: begin, execution count: 1449 Consumer: Waiting waiting at 32 Producer: begin, execution count: 1450 ( depth = 1
Producer: begin, execution count: 1451 Producer: Waiting waiting at 32 waiting out Producer: Waiting waiting at 32
|
现在的问题是,为什么前一个线程执行完的broadcast后,新建的produce线程为什么球会取走,不应该是执行完一个线程再执行同一种线程吗,而且例子中只有一个生产者和一个消费者,缓冲区大小为1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| Producer: begin, execution count: 14397 ( depth = 1 nwait: 0 Producer: begin, execution count: 14398 Producer: Waiting in wait nwait: 1 waiting at 32 nwait: 1 waiting out Producer: Waiting in wait nwait: 1 waiting at 32 Consumer: begin, execution count: 14399 ) depth = 0
nwait: 1 broadcast end Consumer: begin, execution count: 14400 Consumer: Waiting in wait nwait: 1 waiting at 32 waiting out Consumer: Waiting in wait nwait: 2 waiting at 32
|