使用条件变量唤醒线程时,先获取互斥锁的foo为何不会引发死锁?
问题解答
为什么不会触发死锁?
你预设的死锁逻辑的前提是foo线程拿到互斥锁后会一直持有,但实际上pthread_cond_wait接口的内部设计直接避免了这个问题:
当线程调用pthread_cond_wait(&cv, &lock)时,会原子性完成两个操作:
- 释放当前已经持有的互斥锁
lock - 将当前线程加入条件变量
cv的等待队列,进入阻塞状态
这时候锁已经被释放,bar线程就可以正常拿到锁执行后续逻辑:修改dataReady状态、调用pthread_cond_broadcast唤醒等待的foo线程。
而foo线程被唤醒后,pthread_cond_wait会在返回前自动重新获取互斥锁lock,因此后续对共享变量的操作仍然是线程安全的,整个流程不会出现死锁。
补充说明:你贴的代码存在两处笔误,一是foo函数执行完条件判断后重复设置dataReady = true(bar已经完成赋值),二是main函数重复定义,这两处不影响你关心的同步逻辑运行。
该场景是否适合用信号量实现?
完全适合,这种单方向通知的同步场景用信号量实现甚至更简洁,参考实现逻辑如下:
#include <semaphore.h> sem_t sem; void foo(void *arg) { printf ("Foo...\n"); sem_wait(&sem); // 等待bar的通知 printf ("Foo unlocked...\n"); } void bar(void *arg) { printf ("Bar...\n"); sleep(3); printf ("Data ready...\n"); sem_post(&sem); // 发送通知唤醒foo }
两种同步方案的适用场景差异:
- 如果后续需要扩展为多等待线程、需要结合多条件判断的场景,条件变量的灵活性更高
- 如果是这种简单的单次/计数通知场景,信号量的实现代码更精简,不需要额外搭配互斥锁
内容的提问来源于stack exchange,提问作者xyf
相关产品推荐
相关产品推荐

