10-并发控制同步

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);
//但是如果在这里broadcast抢占,先唤醒了,然后nwait=0了,
//就相当于唤醒了另一个同样是生产者或者是消费者线程甚至是自己把球抢走了,再检查条件再进入wait,但是没有线程再放球了就会死锁
P(&cv -> sleep);//这个睡眠和解锁顺序不能更改


mutex_lock(mutex);
}

问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Producer: Broadcast
Consumer: begin, execution count: 1449
Consumer: Waiting
waiting at 32
Producer: begin, execution count: 1450
(
depth = 1
//nwait: 1
//broadcast end
//Producer: Broadcast
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
//Producer: Broadcast
//start broadcast
nwait: 0
//broadcast end
//Consumer: Broadcast
Producer: begin, execution count: 14398
Producer: Waiting
in wait nwait: 1
waiting at 32
//start broadcast
nwait: 1
waiting out
Producer: Waiting
//broadcast end
in wait nwait: 1
waiting at 32
Consumer: begin, execution count: 14399
)
depth = 0
//Consumer: Broadcast
//start broadcast
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