pthread_cond_wait

转载 2011年01月18日 01:11:00

1. 首先pthread_cond_wait 的定义是这样的

The pthread_cond_wait() and pthread_cond_timedwait() functions are used to block on a condition variable. They are called with mutex locked by the calling thread or undefined behaviour will result.

These functions atomically release mutex and cause the calling thread to block on the condition variable cond ; atomically here means "atomically with respect to access by another thread to the mutex and then the condition variable". That is, if another thread is able to acquire the mutex after the about-to-block thread has released it, then a subsequent call to pthread_cond_signal() or pthread_cond_broadcast() in that thread behaves as if it were issued after the about-to-block thread has blocked.

2. 由上解释可以看出,pthread_cond_wait() 必须与pthread_mutex 配套使用。

pthread_cond_wait()函数一进入wait状态就会自动release mutex.

In Thread1:

pthread_mutex_lock(&m_mutex);   
pthread_cond_wait(&m_cond,&m_mutex);   
pthread_mutex_unlock(&m_mutex);  

In Thread2:

pthread_mutex_lock(&m_mutex);   
pthread_cond_signal(&m_cond);   
pthread_mutex_unlock(&m_mutex);  

为什么要与pthread_mutex 一起使用呢? 这是为了应对线程1在调用pthread_cond_wait()但线程1还没有进入wait cond的状态的时候,此时线程2调用了 cond_singal 的情况。 如果不用mutex锁的话,这个cond_singal就丢失了。加了锁的情况是,线程2必须等到 mutex 被释放(也就是 pthread_cod_wait() 进入wait_cond状态 并自动释放mutex) 的时候才能调用cond_singal.

3. pthread_cond_wait() 一旦wait成功获得cond 条件的时候会自动 lock mutex.

这就会出现另一个问题。这是因为

The pthread_cond_wait() and pthread_cond_timedwait() is a cancellation point.

In Thread3:

pthread_cancel(&m_thread);

pthread_join();

因为pthread_cond_wait() and pthread_cond_timedwait()    是线程退出点函数,因此在Thread3中

可以调用pthread_cancel()来退出线程1。那样显然线程1会在 pthread_cond_wait(&m_cond,&m_mutex);    和 pthread_mutex_unlock(&m_mutex); 之间退出,    pthread_cond_wait() 函数返回后自动lock住了mutex, 这个时候线程1退出(并没有运行到pthread_mutex_unlock()),如果Thread2这个时候就再也得不到lock状态了。

通常解决这个问题的办法如下

void cleanup(void *arg)
{
   pthread_mutex_unlock(&mutex);
}
void * thread1(void * arg)
{
    pthread_cleanup_push(cleanup, NULL); // thread cleanup handler
    pthread_mutex_lock(&mutex);
   pthread_cond_wait(&cond, &mutex);
   pthread_mutex_unlock(&mutex);
   pthread_cleanup_pop(0 );
}




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);
              }
              /* operate on x and y */
              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);
              /* modify x and y */
              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);
              }
              /* operate on x and y */
              pthread_mutex_unlock(&mut);

和:       pthread_mutex_lock(&mut);
              /* modify x and y */
              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来进行条件判断,以保证临界区内只有一个线程在处理。

相关文章推荐

游戏服务器端开发要点

摘要: 本文作为游戏服务器端开发的基本大纲,是游戏实践开发中的总结。第一部分专业基础,用于指导招聘和实习考核, 第二部分游戏入门,讲述游戏服务器端开发的基本要点,第三部分服务端架构,介绍架构设计中的一...

数据结构_图_邻接多重表做存储结构遍历无向图_C++实现

示例输入: a b c d e//节点名称 (ctrl+z) 6//边的数目 0 1//每条边连接的两个顶点编号下同 0 3 2 4 ...

C++ map,set内部数据结构

1)Set是一种关联容器,它用于存储数据,并且能从一个数据集合中取出数据。它的每个元素的值必须唯一,而且系统会根据该值来自动将数据排序。每个元素的值不能直接被改变。【重点】内部结构采用红黑树的平衡二叉...

在永康过马路比的就是勇气

在永康过马路比的就是勇气    “在永康过马路比的就是勇气,你永远等不到车辆减慢速度放你过去,就算在人行横道,等来的也是喇叭声和呼啸而过的那么寂寞。”笔者与在永康工作的很多同事聊天中,一致觉得在永康过...

什么是SDK 和JDK

什么是SDK 和JDK SDK是Software Development Kit的缩写,中文意思是“软件开发工具包”。这是一个覆盖面相当广泛的名词,可以这么说:辅助开发某一类软件的相关文档、范例和工...

pthread_cond_wait详解

  • 2015-03-20 11:34
  • 1.15MB
  • 下载

信号pthread_cond_wait

  • 2011-05-17 23:49
  • 344KB
  • 下载

pthread_cond_wait()太难理解了

了解 pthread_cond_wait() 的作用非常重要 -- 它是 POSIX 线程信号发送系统的核心,也是最难以理解的部分。 首先,让我们考虑以下情况:线程为查看已链接列表而锁定了互斥对象...

线程通信与pthread_cond_wait()的使用

pthread_cond_wait() /************pthread_cond_wait()的使用方法**********/     pthread_mutex_lock(&q...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)