解析1

LINUX环境下多线程编程肯定会遇到需要条件变量的情况,此时必然要使用pthread_cond_wait()函数。但这个函数的执行过程比较难于理解。

pthread_cond_wait()的工作流程如下(以MAN中的EXAMPLE为例):
      
Consider two shared variables x and y, protected by the mutex mut,
and a condition vari-
      
able cond that is to be signaled whenever x becomes greater than
y.

int x,y;
             
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
             
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

Waiting until x is greater than y is performed as
follows:

pthread_mutex_lock(&mut);
             
while (x <= y) {
                     
pthread_cond_wait(&cond,
&mut);
             
}

pthread_mutex_unlock(&mut);

Modifications on x and y that may cause x to become greater than y
should signal the con-
      
dition if needed:

pthread_mutex_lock(&mut);

if (x > y)
pthread_cond_broadcast(&cond);
             
pthread_mutex_unlock(&mut);

这个例子的意思是,两个线程要修改X和
Y的值,第一个线程当X<=Y时就挂起,直到X>Y时才继续执行(由第二个线程可能会修改X,Y的值,当X>Y时唤醒第一个线程),即
首先初始化一个普通互斥量mut和一个条件变量cond。之后分别在两个线程中分别执行如下函数体:

pthread_mutex_lock(&mut);

while (x <= y) {
                     
pthread_cond_wait(&cond,
&mut);
             
}

pthread_mutex_unlock(&mut);

   
 while作用:因为可能有多个线程等待,所以 pthread_cond_wait 返回时,假如A线程会先获取mut,此时其他线程变阻塞,如果A修改了x,y使x<=y则其他线程就没必要再执行了,所以要加while判断。

和:       pthread_mutex_lock(&mut);

if (x > y)
pthread_cond_signal(&cond);
             
pthread_mutex_unlock(&mut);

其实函数的执行过程非常简单,在第一个线程执行到pthread_cond_wait(&cond,&mut)时,此时如果X<=Y,则此函数就将mut互斥量解锁 ,再将cond条件变量加锁 ,此时第一个线程挂起 (不占用任何CPU周期)。

而在第二个线程中,本来因为mut被第一个线程锁住而阻塞,此时因为mut已经释放,所以可以获得锁mut,并且进行修改X和Y的值,在修改之后,一个IF语句判定是不是X>Y,如果是,则此时pthread_cond_signal()函数会唤醒第一个线程 ,并在下一句中释放互斥量mut。然后第一个线程开始从pthread_cond_wait()执行,首先要再次锁mut ,
如果锁成功,再进行条件的判断 (至于为什么用WHILE,即在被唤醒之后还要再判断,后面有原因分析),如果满足条件,则被唤醒 进行处理,最后释放互斥量mut 。

至于为什么在被唤醒之后还要再次进行条件判断(即为什么要使用while循环来判断条件),是因为可能有“惊群效应”。有人觉得此处既然是被唤醒的,肯定
是满足条件了,其实不然。如果是多个线程都在等待这个条件,而同时只能有一个线程进行处理,此时就必须要再次条件判断,以使只有一个线程进入临界区处理。
对此,转来一段:

引用下POSIX的RATIONALE:

Condition Wait Semantics

It is important to note that when pthread_cond_wait() and
pthread_cond_timedwait() return without error, the associated
predicate may still be false. Similarly, when
pthread_cond_timedwait() returns with the timeout error, the
associated predicate may be true due to an unavoidable race between
the expiration of the timeout and the predicate state
change.

The application needs to recheck the predicate on any return
because it cannot be sure there is another thread waiting on the
thread to handle the signal, and if there is not then the signal is
lost. The burden is on the application to check the
predicate.

Some implementations, particularly on a multi-processor, may
sometimes cause multiple threads to wake up when the condition
variable is signaled simultaneously on different
processors.

In general, whenever a condition wait returns, the thread has to
re-evaluate the predicate associated with the condition wait to
determine whether it can safely proceed, should wait again, or
should declare a timeout. A return from the wait does not imply
that the associated predicate is either true or
false.

It is thus recommended that a condition wait be enclosed in the
equivalent of a "while loop" that checks the
predicate.

从上文可以看出: 
1,pthread_cond_signal在多处理器上可能同时唤醒多个线程,当你只能让一个线程处理某个任务时,其它被唤醒的线程就需要继续
wait,while循环的意义就体现在这里了,而且规范要求pthread_cond_signal至少唤醒一个pthread_cond_wait上
的线程,其实有些实现为了简单在单处理器上也会唤醒多个线程. 
2,某些应用,如线程池,pthread_cond_broadcast唤醒全部线程,但我们通常只需要一部分线程去做执行任务,所以其它的线程需要继续wait.所以强烈推荐此处使用while循环.

其实说白了很简单,就是pthread_cond_signal()也可能唤醒多个线程,而如果你同时只允许一个线程访问的话,就必须要使用while来进行条件判断,以保证临界区内只有一个线程在处理。

解析2

2.使用条件变量的线程同步(推荐)

采用阻塞和消息方式可以极大程度上减少资源的浪费以及增加实时性

线程条件变量pthread_cond_t

线程等待某个条件

int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime);

int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);

通知函数

通知所有的线程

int pthread_cond_broadcast(pthread_cond_t *cond);

只通知一个线程

int pthread_cond_signal(pthread_cond_t *cond);

---------------------------------------------------------------------------------

正确的使用方法

pthread_cond_wait用法:

pthread_mutex_lock(&mutex);

while(condition_is_false)

{

pthread_cond_wait(&cond,&mutex);

}

condition_is_false=true;  //此操作是带锁的,也就是说只有一个线程同时进入这块

pthread_mutex_unlock(&mutex);

----------------------------------------------------

pthread_cond_signal用法: 

pthread_mutex_lock(&mutex);

condition_is_false=false;

pthread_cond_signal(&cond)

pthread_mutex_unlock(&mutex)

--------------------------------------------------------

记住上面这种用法!!!可以避免误用pthread_cond_broadcast而释放了所有条件变量

参考 http://blog.csdn.net/mashang123456789/article/details/9792677

Linux 线程管理的更多相关文章

  1. Linux之线程管理

    linux下查看线程数的几种方法   1. cat /proc/${pid}/status [root@limt01 2325]# ps -ef|grep xinetd|grep -v grep ro ...

  2. Linux进程管理 (篇外)内核线程简要介绍

    关键词:kthread.irq.ksoftirqd.kworker.workqueues 在使用ps查看线程的时候,会有不少[...]名称的线程,这些有别于其它线程,都是内核线程. 其中多数内核线程从 ...

  3. Linux进程管理 (篇外)内核线程简要介绍【转】

    转自:https://www.cnblogs.com/arnoldlu/p/8336998.html 关键词:kthread.irq.ksoftirqd.kworker.workqueues 在使用p ...

  4. linux内存管理

    一.Linux 进程在内存中的数据结构 一个可执行程序在存储(没有调入内存)时分为代码段,数据段,未初始化数据段三部分:    1) 代码段:存放CPU执行的机器指令.通常代码区是共享的,即其它执行程 ...

  5. [转载]Linux 线程实现机制分析

    本文转自http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/ 支持原创.尊重原创,分享知识! 自从多线程编程的概念出现在 Linux ...

  6. Linux进程管理子系统分析【转】

    本文转载自:http://blog.csdn.net/coding__madman/article/details/51298732 Linux进程管理: 进程与程序: 程序:存放在磁盘上的一系列代码 ...

  7. Linux内存管理原理

    本文以32位机器为准,串讲一些内存管理的知识点. 1. 虚拟地址.物理地址.逻辑地址.线性地址 虚拟地址又叫线性地址.linux没有采用分段机制,所以逻辑地址和虚拟地址(线性地址)(在用户态,内核态逻 ...

  8. linux线程的实现

    首先从OS设计原理上阐明三种线程:内核线程.轻量级进程.用户线程 内核线程 内核线程就是内核的分身,一个分身可以处理一件特定事情.这在处理异步事件如异步IO时特别有用.内核线程的使用是廉价的,唯一使用 ...

  9. linux线程的实现【转】

    转自:http://www.cnblogs.com/zhaoyl/p/3620204.html 首先从OS设计原理上阐明三种线程:内核线程.轻量级进程.用户线程 内核线程 内核线程就是内核的分身,一个 ...

随机推荐

  1. wifi万能钥pc版提示手机未连接

     关于PC版万能钥匙的用法 大部分人都是在“未连接到手机”再不知道怎么搞了 怎么连接到手机呢? 首先要把你的手机变成路由器 让电脑连上 这个都知道怎么搞吧 手机版万能钥匙有个一键让手机变成热点 再用电 ...

  2. ASP.MVC时间类型json数据处理

    服务端返回DateTime属性如果用自带的json方法返回的数据如下: 有2种办法解决一种是采用服务端解决方案,一种是使用前端解决方案 1.前端解决方案 第一步:对Date进行扩展 // 对Date的 ...

  3. Javascript的原型链图

    90%的前端或者js程序员或者老师们对Javascript懂得不比这个多 给手机看的 但是这个图里的所有褐色单向箭头链就是Javascript的原型链(颜色标注对理解js原型链很关键) 这图中的各个_ ...

  4. linux大文件分割 split命令

    inux split 命令 功能说明:切割文件. 语 法:split [--help][--version][-][-b ][-C ][-l ][要切割的文件][输出文件名] 补充说明:split可将 ...

  5. SQL 通过syscolumns.xtype动态查找指定数据类型字段所包含的数据

    表中太多列,只想查找某些比如,数据类型为varchar的字段的数据. 思路:1.先获取列名: select * from syscolumns where id=(select max(id) fro ...

  6. D3.js学习(三)

    上一节中,我们已经画出了图表,并且给图表添加了坐标轴的标签和标题,在这一节中,我们将要学习几个绘制线条不同特性的几个函数,以及给图表添加格栅.ok,进入话题! 如何给线条设置绘制的样式? 这个其实非常 ...

  7. NDK 笔记(一)

    参考:https://developer.android.com/studio/projects/add-native-code.html#link-gradle 使用Android Studio 2 ...

  8. jQuery sibings()的作用

    jQuery sibings()的作用: siblings() 获得匹配集合中每个元素的同胞,通过选择器进行筛选是可选的. 当我们要对一个<li></li>列表的操作的时候,只 ...

  9. HDU4329

    #include<cstdio> #include<algorithm> #include<map> using namespace std; int main() ...

  10. org.springframework.web.servlet.PageNotFound - No mapping found for HTTP request with URI [XXX] in DispatcherServlet with name 'springMVC'

    在web.xml中添加 <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern ...