转:http://blog.csdn.net/aniao/article/details/5802015

APUE上,关于条件锁。其中有这么几条总结:

1.使用条件锁前必须先锁住对应的互斥锁。

2.条件锁进入阻塞(pthread_cond_wait)时自动解开对应互斥锁,而一旦跳出阻塞立即再次取得互斥锁,而这两个操作都是原子操作。

好,现在考虑到这一点,假如有如下函数:

void* run(void *s)
{
pthread_mutex_lock(&mutex);
while(i == )
{
printf("线程%u进入等待状态\n", (unsigned int)pthread_self());
pthread_cond_wait(&cond_l, &mutex);
}
printf("已经解开%u\n", (unsigned int)pthread_self());
pthread_mutex_unlock(&mutex);
i = ; return ((void *) );
}

根据前面两条规则,我们可以知道,如果多个线程同时调用这个函数,当一个线程取得同步锁之后,其他线程就会阻塞在pthread_mutex_lock函数,而当那个取得锁的线程执行到pthread_cond_wait并阻塞之后,在从这个函数返回(条件满足)之前,会释放掉锁,所以其他线程也能一个一个都执行到pthread_cond_wait这里阻塞。这时就有多个线程阻塞在这里了。

假设这时候在另外某个线程条件被满足,并发出了pthread_cond_signal,那么这么多阻塞的线程会不会全部一下就都被解开了呢?

答案是否。

因为根据第二条规则,从阻塞的函数返回并尝试再次锁住互斥锁,这是一个原子操作。也就是说,第一个成功解套的线程会再次锁上互斥锁,而其他线程这时候要想跳出阻塞状态就不可能了,因为他们无法取得互斥锁,只能继续等待(根据我的测试是等待下一次pthread_cond_singal。

(以上是错误的,后来发现,原来pthread_cond_signal本来就只会唤醒一个条件锁,而实验证明,唤醒的顺序跟阻塞在条件锁的顺序相同)

#include <stdio.h>
#include <error.h>
#include <pthread.h>
#include <unistd.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_l = PTHREAD_COND_INITIALIZER; int i = ;
void* run(void *); void main(int argc, char **argv)
{
pthread_t pid1;
pthread_t pid2;
pthread_t pid3;
pthread_t pid4; pthread_create(&pid1, NULL, run, NULL );
printf("new thread:%u\n", (unsigned int)pid1);
sleep(); pthread_create(&pid2, NULL, run, NULL );
printf("new thread:%u\n", (unsigned int)pid2);
sleep(); pthread_create(&pid3, NULL, run, NULL );
printf("new thread:%u\n", (unsigned int)pid3);
sleep(); pthread_create(&pid4, NULL, run, NULL );
printf("new thread:%u\n", (unsigned int)pid4);
sleep(); //修改
//pthread_mutex_lock(&mutex); i = ;
pthread_cond_signal(&cond_l);
printf("release signal\n");
sleep(); i = ;
pthread_cond_signal(&cond_l);
printf("release signal\n");
sleep(); pthread_join(pid1, NULL );
pthread_join(pid2, NULL );
pthread_join(pid3, NULL );
pthread_join(pid4, NULL );
} void* run(void *s)
{
pthread_mutex_lock(&mutex);
while(i == )
{
printf("线程%u进入等待状态\n", (unsigned int)pthread_self());
pthread_cond_wait(&cond_l, &mutex);
}
printf("已经解开%u\n", (unsigned int)pthread_self());
pthread_mutex_unlock(&mutex);
i = ; return ((void *) );
}

最后的输出是:

new thread:3085007776

线程3085007776进入等待状态

new thread:3076615072

线程3076615072进入等待状态

new thread:3068222368

线程3068222368进入等待状态

new thread:3059829664

线程3059829664进入等待状态

release signal

已经解开3085007776

release signal

已经解开3076615072

一切正常,每次pthread_cond_signal就能放掉一个线程。那么为了验证前面我的分析是正确的,加入在执行pthread_cond_signal的时候,阻塞在对应条件锁的pthread_cond_wait处的线程的互斥锁全都是被锁住的,还会有线程能成功解套么?看以下代码:

#include <stdio.h>
#include <error.h>
#include <pthread.h>
#include <unistd.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_l = PTHREAD_COND_INITIALIZER; int i = ;
void* run(void *); void main(int argc, char **argv)
{
pthread_t pid1;
pthread_t pid2;
pthread_t pid3;
pthread_t pid4; pthread_create(&pid1, NULL, run, NULL );
printf("new thread:%u\n", (unsigned int)pid1);
sleep(); pthread_create(&pid2, NULL, run, NULL );
printf("new thread:%u\n", (unsigned int)pid2);
sleep(); pthread_create(&pid3, NULL, run, NULL );
printf("new thread:%u\n", (unsigned int)pid3);
sleep(); pthread_create(&pid4, NULL, run, NULL );
printf("new thread:%u\n", (unsigned int)pid4);
sleep(); //修改
pthread_mutex_lock(&mutex); i = ;
pthread_cond_signal(&cond_l);
printf("release signal\n");
sleep(); i = ;
pthread_cond_signal(&cond_l);
printf("release signal\n");
sleep(); pthread_join(pid1, NULL );
pthread_join(pid2, NULL );
pthread_join(pid3, NULL );
pthread_join(pid4, NULL );
} void* run(void *s)
{
pthread_mutex_lock(&mutex);
while(i == )
{
printf("线程%u进入等待状态\n", (unsigned int)pthread_self());
pthread_cond_wait(&cond_l, &mutex);
}
printf("已经解开%u\n", (unsigned int)pthread_self());
pthread_mutex_unlock(&mutex);
i = ; return ((void *) );
}

注意带注释的地方,在执行pthread_cond_signal之前,我又把互斥锁锁住了。之所以这里敢这么写,是因为其他几个子线程最后卡在pthread_cond_wait的时候都会把锁给释放掉的,所以我能在主线程里取得互斥锁。这样的话,其他子线程接到条件满足的信号后还会从等待中跳出来吗?运行结果如下:

new thread:3085290400

线程3085290400进入等待状态

new thread:3076897696

线程3076897696进入等待状态

new thread:3068504992

线程3068504992进入等待状态

new thread:3060112288

线程3060112288进入等待状态

release signal

release signal

Oh,No,果然,没有一个线程跑出来。事实上,如果不是这么改,而是让每个线程在run函数最后不释放互斥锁,最后只会有第一个跑出来的线程解套成功。所以,从目前来看,我的分析应该是正确的。

关于一点pthread_cond_t条件锁的思考以及实验的更多相关文章

  1. Linux 开发之线程条件锁那些事

    2019独角兽企业重金招聘Python工程师标准>>> 条件锁即在一定条件下触发,那什么时候适合用条件锁呢,那当然是你在等待一个符合的条件下触发.一个常用的例子就是在线程中无限循环执 ...

  2. 47. Permutations II(medium, backtrack, 重要, 条件较难思考)

    Given a collection of numbers that might contain duplicates, return all possible unique permutations ...

  3. python线程condition条件锁应用实例

    import time import threading # 吃火锅鱼丸 guo = [] suo = threading.Condition() #条件锁 # 生产者负责生产 class Produ ...

  4. Python的条件锁与事件共享

    1:事件机制共享队列: 利用消息机制在两个队列中,通过传递消息,实现可以控制的生产者消费者问题要求:readthread读时,writethread不能写:writethread写时,readthre ...

  5. 死磕 java同步系列之ReentrantLock源码解析(二)——条件锁

    问题 (1)条件锁是什么? (2)条件锁适用于什么场景? (3)条件锁的await()是在其它线程signal()的时候唤醒的吗? 简介 条件锁,是指在获取锁之后发现当前业务场景自己无法处理,而需要等 ...

  6. 深入理解java:2.3.2. 并发编程concurrent包 之重入锁/读写锁/条件锁

    重入锁 Java中的重入锁(即ReentrantLock)   与JVM内置锁(即synchronized)一样,是一种排它锁. ReentrantLock提供了多样化的同步,比如有时间限制的同步(定 ...

  7. 条件锁Condition

    """设计场景:timo先说一句,亚索再说一句timo: timo队长正在待命yasuo: 面对疾风吧timo: timo整装待发yasuo: 哈杀gay "& ...

  8. 关于web多标签多条件筛选的思考以及缓存的正确使用方法(上)

    做项目的过程中,发现一次远程链接数据库的耗时大概是300ms~400ms,切身体会到了前辈们经常说的减少链接的重要性,用了缓存后页面的打开时间从1.5s减少到400ms 前提: 那么来说一说正题,we ...

  9. 条件锁condition与Queue()

    在学习之前你应该先了解锁和队列基础 import queue import time import random import threading import asyncio import logg ...

随机推荐

  1. 【LeetCode】214. Shortest Palindrome

    Shortest Palindrome Given a string S, you are allowed to convert it to a palindrome by adding charac ...

  2. mount 需要同时设置 noatime 和 nodiratime 吗?

    相信对性能.优化这些关键字有兴趣的朋友都知道在 Linux 下面挂载文件系统的时候设置 noatime 可以显著提高文件系统的性能.默认情况下,Linux ext2/ext3 文件系统在文件被访问.创 ...

  3. Eclipse中创建Maven多模块工程

    1.先创建父项目 在Eclipse里面New -> Maven Project: 在弹出界面中选择“Create a simple project” 这样,我们就按常规模版创建了一个Maven工 ...

  4. 使用grep恢复被删文件内容

    在Unix/Linux下,最危险的命令恐怕就属rm命令了,每次在root下使用这个命令的时候,我都要盯着命令行看上几分钟才敢把回车敲下去.以前,看到同事在脚本中使用rm命令 —— rm {$App_D ...

  5. mfc怎么显示jpg png图像

    如果是VS2005以上版本可以直接使用MFC自带的CImage类,如果不是可以用网上比较流行的CxImage,或者使用GDI+

  6. SharePoint 2013 Farm 安装指南——Least Privilege

    写过很多关于SharePoint 2013 安装,这是第四篇.可能你会觉得为什么如此简单的安装至于花那么多精力去折腾吗.我的答案是肯定的.知识的积累不是一蹴而就的,而是循序渐进的去学习,每一个阶段都有 ...

  7. 使用Python3自带工具2to3.py 转换 Python2.x 代码 到Python3

    几乎所有的Python 2程序都需要一些修改才能正常地运行在Python 3的环境下.为了简化这个转换过程,Python 3自带了一个叫做2to3的实用脚本(Utility Script),这个脚本会 ...

  8. winform中键盘和鼠标事件的捕捉和重写

    在编写winform应用程序时,有时需要无论在哪个控件获取焦点时,对某一个键盘输入或者鼠标事件都进行同样的操作.比如编写一个处理图片的应用程序时,希望无论当前哪个控件获得焦点,当用户按上.下.左.右键 ...

  9. 【转载】centos7.3 防火墙配置

    firewalld介绍原文:https://www.cnblogs.com/moxiaoan/p/5683743.html 一. centos7 默认有一个防火墙 firewalld,具体使用如下: ...

  10. nginx 443 https mark

    #user  nobody; worker_processes  4; #error_log  logs/error.log; #error_log  logs/error.log  notice; ...