网站首页 > 技术文章 正文
条件变量可以解决线程同步和共享资源访问的问题,条件变量是对互斥锁的补充,它允许一个线程阻塞并等待另一个线程发送的信号,当收到信号时,阻塞的线程被唤醒并试图锁定与之相关的互斥锁。具体定义如下:
等待:
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abtime);
唤醒:
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
具体使用场景:
在等待线程实现如下:
pthread_mutex_lock(&same_mutex);
pthread_cond_wait(&m_cond, &same_mutex);
pthread_mutex_unlock(&same_mutex);
在唤醒线程实现如下:
pthread_mutex_lock(&same_mutex);
pthread_cond_signal(&m_cond);
pthread_mutex_unlock(&same_mutex);
等待线程会在pthread_cond_wait()调用时挂起,并且在锁的保护下构造和检查好m_cond对应的条件链表后先解锁same_mutex,然后睡眠。这里解锁和睡眠是一个原子操作。当等待线程收到唤醒线程的通知后,pthread_cond_wait做的第一件事是把same_mutex重新加锁并唤醒返回,这里加锁和唤醒也是一个原子操作。
那么唤醒线程和等待线程为什么要用同一个mutex锁呢?首先,如果在等待线程调用了pthread_cond_wait()但是还没有开始等待(因为之前还要做链表的初始化工作),这时唤醒操作如果发生则会导致唤醒丢失(竞态条件)。因此必须使用锁防止条件链表这个共享资源被同时操作。(等待线程先在锁保护下操作完共享链表,然后解锁和睡眠是原子操作后开始睡眠,因此唤醒操作如果是在同一把锁保护中才能唤醒的话(唤醒也会修改共享链表),等待线程一定已经访问完共享资源并且睡眠了,就防止了冲突丢失唤醒信号)。 但是如果当前没有线程阻塞等待唤醒,pthread_cond_signal()函数调用后应没有任何效果。
因此条件变量使用锁是为了防止唤醒和等待操作同时发生的竞态条件,从而导致唤醒丢失甚至引起死锁。但是如果是认为不等待直接唤醒则该唤醒会直接丢失。
注:
最后pthread_cond_wait唤醒和加锁也是一个原子操作,如果有多个线程在同一个条件变量上等待,可以保证虽然都被唤醒了但是只有一个线程会获取到锁。
猜你喜欢
- 2025-05-15 穿透与击穿:缓存世界的两场“攻击”,Java工程师如何见招拆招?
- 2025-05-15 一篇文章快速搞懂C++线程同步机制
- 2025-05-15 C语言编写多线程,什么时候要使用互斥锁?为什么要使用互斥锁?
- 2025-05-15 go语言并发原语RWMutex实现原理及闭坑指南
- 2025-05-15 实战经验:一次错误使用 go-cache 包导致出现的线上问题
- 2025-05-15 3. 复合数据类型
- 2025-05-15 Linux ALSA 音频系统:物理链路篇02
- 2025-05-15 聊聊并发编程: Lock
- 2025-05-15 Golang语言如何实现并行和并发
- 2025-05-15 C++防御性编程,提高代码的健壮性
- 最近发表
- 标签列表
-
- axure 注册码 (25)
- exploit db (21)
- mutex_lock (30)
- oracleclient (27)
- think in java (14)
- javascript权威指南 (19)
- nfs (25)
- componentart (17)
- yii框架 (14)
- springbatch (28)
- oracle数据库备份 (25)
- iptables (21)
- 自动化单元测试 (18)
- python编写软件 (14)
- dir (26)
- connectionstring属性尚未初始化 (23)
- output (32)
- panel滚动条 (28)
- centos 5 4 (23)
- sql学习 (33)
- dfn (14)
- http error 503 (21)
- pop3服务器 (18)
- 图表组件 (17)
- android退出应用 (21)