linux线程锁的迷思
来源:互联网 发布:合肥市大数据企业 编辑:程序博客网 时间:2024/05/22 15:09
http://www.ibm.com/developerworks/cn/linux/thread/posix_thread3/#1
当多线程想要等待某一条件成立时,用pthread_cond_wait来阻塞线程,
- 首先明确wait的作用,pthread的wait与lock都可以阻塞线程等待“条件”成立,区别在于:
wait之后的发送来的条件成立(pthread_cond_broadcast())才有效,之前发生都被丢弃了,也就是说wait的首次调用肯定会阻塞线程,不会因条件成立过而向下运行;
而lock的条件在成立(信号量未被别人lock )后会一直维持 unlock的状态,那么线程首次调用lock就不一定会阻塞,而取决于“条件”状态。
- 那么问题来了,为什么pthread_cond_wait调用之前必须保证本线程已经被lock了?为什么wait要被设计成这样?
据说是因为wait时如果有条件达成,会因为wait未能及时加入到队列中而错失这个条件,只是这样吗?
试一下就知道了,本线程未被lock时调用wait也是可以的,wait也能正常工作啊。
下面用测试代码来说明这个问题:
void * foo1(void * p){ while(1){ printf("foo1 wait begin\n"); pthread_cond_wait(&c,&m); printf("foo1 wait end\n");sleep(1); }}void * foo2(void * p){ while(1){ printf("foo2 wait begin\n"); pthread_cond_wait(&c,&m); printf("foo2 wait end\n");sleep(1); }}void * foo3(void * p){ while(1){ getchar(); pthread_cond_broadcast(&c); }}int pthreadTest(){ pthread_t tid[10]; pthread_create(tid+2,NULL,foo1,NULL); pthread_create(tid+1,NULL,foo2,NULL); pthread_create(tid+3,NULL,foo3,NULL); pthread_join(*(tid+1),NULL); pthread_join(*(tid+2),NULL);}结果foo2 wait end
foo2 wait begin
foo1 wait end
foo1 wait begin
foo2 wait end
foo2 wait begin
foo1 wait end
foo1 wait begin从结果上看 wait唤醒的时候会lock住mutex,当线程循环一遍后再次调用wait而释放mutex时 再唤醒其他线程。
那么,线程间使用不同的mutex是否就可以同时唤醒两个线程的wait了呢,也就是是否就能够单纯的用cond控制wait唤醒?每个线程一个mutex,这样就不会被其他线程锁住自己的信号量了吧,下面测试一下:
void * foo1(void * p){ while(1){ printf("foo1 wait begin\n"); pthread_cond_wait(&c,&m11111); printf("foo1 wait end\n");sleep(1); }}void * foo2(void * p){ while(1){ printf("foo2 wait begin\n"); pthread_cond_wait(&c,&m22222); printf("foo2 wait end\n");sleep(1); }}
结果:foo2 wait end
foo2 wait begin
foo2 wait end
foo2 wait begin这?????,只唤醒了一个线程(具体唤醒哪个线程取决于哪个线程先执行),pthread_cond_broadcast声称激活所有等待线程,但看来并不简单,可能是wait的时候同一个cond是事实上他的激活方式是串行的(也就是每次的pthread_cond_signal后根据wait的情况决定下一次是否signal),另一种可能是后运行的线程的mutex出现了问题。
那么将pthread_cond_broadcast改成pthread_cond_signal后测试看看,结果:
foo1 wait end
foo1 wait begin
foo2 wait end
foo2 wait begin
foo1 wait end
foo1 wait begin
foo2 wait end
foo2 wait begin这是否说明了与mutex无关而激活方式确实是串行的呢?再试试每次pthread_cond_broadcast后调用unlock(&m11111),结果:
foo1 wait end
foo2 wait endfoo1 wait begin
foo2 wait begin
foo1 wait end
foo2 wait endfoo1 wait begin
foo2 wait begin恩,看来应该是后运行的线程在wait唤醒时无法lock自己的mutex,但是根据刚才signal的结果看,这又是谁lock了它的mutex呢?
经过思考,终于把自己搞晕了......一个问题如果不能理解,那就会产生宗教,比如:“别问为什么,书上就是这么说的!”
所以 真正的原因就是:一个特定条件只能有一个互斥对象,而且条件变量应该表示互斥数据“内部”的一种特殊的条件更改。一个互斥对象可以用许多条件变量(例如,cond_empty、cond_full、cond_cleanup),但每个条件变量只能有一个互斥对象。
同时,wait也只有一个正确用法:如果线程正在等待某个特定条件发生,它应该如何处理这种情况?它可以重复对互斥对象锁定和解锁,每次都会检查共享数据结构,以查找某个值。但这是在浪费时间和资源,而且这种繁忙查询的效率非常低。解决这个问题的最佳方法是使用 pthread_cond_wait() 调用来等待特殊条件发生。
所以我们记住这个结论:照着他这么用就得了......否则只会走火入魔
- linux线程锁的迷思
- android进程/线程的迷思
- 学习嵌入式和linux的迷思
- Union的迷思
- 关于地址的迷思....
- 封建制度的迷思
- 傳統經理人的迷思(转)
- SEO资料的迷思
- 程序员的迷思
- MVC的迷思
- 跳槽的迷思
- 软件行业的迷思
- Assigned 的迷思
- 操作系统的迷思
- 内存整理的迷思
- 重构的迷思
- 设计的迷思
- Union的迷思
- SQL的将EXEC()动态执行的结果集放到一张临时表
- 教育部:大学生不得在同一城市转学
- 第十三周 项目一(3):动物这样叫(数据成员name)
- Cookie/Session机制详解
- GRE词汇词根记忆:flu
- linux线程锁的迷思
- 纯前端的图片预览
- 堆和栈的区别(经典)
- linux 下重命名一个文件
- iptables 备忘
- Spark Streaming+kafka+eclipse编程
- IOS工程自动打包并发布脚本实现
- SQLServer游标(Cursor)简介和使用说明
- iOS中属性与成员变量的区别