【发布时间】:2020-06-30 07:06:02
【问题描述】:
以下是书中给出的代码来说明一个问题: 当有 1 个生产者 Tp 和 2 个消费者 Tc1,Tc2 时,以下代码将不起作用。 原因是当 Tp 将数据放入队列时,它唤醒了 Tc1,在 Tc1 运行之前,Tc2 潜入并取出唯一的元素,从而清空队列。然后 Tc1 开始调用 get() ,因为队列为空,所以会抛出异常。并且书籍建议将“if(count ==0)”替换为“while(count == 0)”,这样可以确保 Tc1 的状态在它运行之前是需要的。
只有当 Tc2 确实有办法在 Tc1 之前潜入时,我才有意义。如果 Tp 调用 notify 来唤醒 Tc1,则 Tc1 可能会抢到锁,在这种情况下 Tc2 将无法潜入并做任何事情。如果 Tc1 确实未能抓住锁而 Tc2 确实如此,那么 Tc1 应该回到睡眠状态,直到它再次收到通知。在那种情况下,它永远不会进入 get() 行。
所以我的问题是:如果 Tc1 抓住锁,为什么 Tc2 会在 Tc1 之前潜入并做任何事情?
cond_t cond;
2 mutex_t mutex;
3
4 void *producer(void *arg) {
5 int i;
6 for (i = 0; i < loops; i++) {
7 Pthread_mutex_lock(&mutex); // p1
8 if(count == 1) // p2
9 Pthread_cond_wait(&cond, &mutex); // p3
10 put(i); // p4
11 Pthread_cond_signal(&cond); // p5
12 Pthread_mutex_unlock(&mutex); // p6
13 }
14 }
15
16 void *consumer(void *arg) {
17 int i;
18 for (i = 0; i < loops; i++) {
19 Pthread_mutex_lock(&mutex); // c1
20 if(count == 0) // c2
21 Pthread_cond_wait(&cond, &mutex); // c3
22 int tmp = get(); // c4
23 Pthread_cond_signal(&cond); // c5
24 Pthread_mutex_unlock(&mutex); // c6
25 printf("%d\n", tmp);
26 }
27 }
【问题讨论】:
-
Pthread_cond_signal至少唤醒一个线程,因此两个线程都可能被唤醒 -
@AlanBirtles 如果我使用来自 c++ lib 的条件变量并调用 notify_one 会有所不同吗?能保证只唤醒一个吗?
-
@AlanBirtles 也是,即使 Pthread_cond_signal 唤醒 2,应该只有一个成功锁定,另一个应该进入睡眠?
-
不明白,如果两个都可以以这种方式抢到锁,那么这里加锁的目的是什么?
-
是的,一次只会唤醒一个,但是一旦第一个完成执行并释放锁,第二个就可以获取锁并开始执行
标签: c++ concurrency locking