如果pthread_cond_wait自己执行此操作,那么锁定和解锁互斥锁的重点是什么?

时间:2014-10-27 05:36:36

标签: c++ pthreads mutex

我试图了解互斥锁和条件变量之间的区别,并对以下代码感到困惑。

// Lock mutex and then wait for signal to relase mutex
pthread_mutex_lock( &count_mutex );

/*Wait while functionCount2() operates on count
mutex unlocked if condition varialbe in functionCount2() signaled. <-- so then why call pthread_mutex_unlock() 3 lines latter if it's already unlocked?*/
pthread_cond_wait( &condition_var, &count_mutex );
count++;
printf("Counter value functionCount1: %d\n",count);

pthread_mutex_unlock( &count_mutex );

根据the docs pthread_cond_wait()&#34;原子释放互斥锁并导致调用线程阻塞条件变量&#34;那么pthread_mutex_lock( &count_mutex );如果pthread_cond_wait()解锁它是什么,以及后者调用pthread_mutex_unlock()的重点是什么,因为pthread_cond_wait()已经解锁了它?< / p>

对我而言,如果pthread_cond_wait()没有使用互斥量,那将是有意义的,我认为这是重点。

2 个答案:

答案 0 :(得分:4)

首先让我们定义一些可能有点令人困惑的术语:

  • condition:这是线程用来确定是否发生了某些事情或需要完成工作的表达式。例如,条件可能是队列不为空。

  • 条件变量:这是一个同步对象,pthread库(或类似的东西)可以让线程等待条件发生变化。线程可以等待&#39;在条件变量上,当另一个线程发出该条件变量的信号时,等待的线程将被唤醒。

请注意&#34;条件&#34;与&#34;条件变量&#34;不同的是。

当使用条件变量时,线程需要检查条件(无论是什么),如果条件不满足,它可以等待条件变量,直到某些信号表明它应该再次检查条件。

然而,这一系列事件:

  1. 检查条件
  2. 等待条件变量
  3. 本身不是原子的 - 如果在步骤1和2之间另一个线程发出条件变量的信号,那么等待的线程可能永远不会被唤醒(条件变量不记得过去发生了一个信号) ;当发出信号时,他们只会解锁已经在等待的线程。为了避免这个问题,条件变量必须与一个模式一起使用,以确保这两个步骤将相对于处理条件和条件变量的其他线程以原子方式发生。那种模式是:

    • 读取或更新条件中使用的对象的任何线程必须在执行此操作时持有互斥锁。请注意,这包括可能在条件变量上等待的线程。
    • 在等待条件变量时,在保持互斥锁的同时检查条件的线程必须继续保持pthread_cond_wait()调用的互斥锁。这可以确保上面的步骤1和2之间的竞争条件不会发生,因为在pthread_cond_wait()调用准备线程等待之前,更新条件的任何内容都将无法获取互斥锁。此时pthread_cond_wait()函数将释放互斥锁,这将允许更新线程获取互斥锁并更新条件。

答案 1 :(得分:0)

让我们看看以下两个功能,等待通知。两者都在两个独立的线程中运行,并使用全局定义的变量互斥 cond 。 我们假设等待线程首先启动并锁定互斥锁。现在条件“值为零”可以安全地测试,因为锁保证没有其他线程可以改变。在下一步中,我们的等待线程正在等待来自通知函数的信号的条件变量已更改并且它应该再次检查。

void* waiting(void* arg)
{
  pthread_mutex_lock(&mutex);
  while(value == 0)
  {
    pthread_cond_wait(&cond, &mutex);
  }

  printf("waiter %d releases\n", *tid);
  pthread_mutex_unlock(&mutex);

}

现在让我们看看通知功能的用途。你还记得我们在等待主题中锁定了互斥吗?如果不发布,我们的通知功能永远无法获得互斥并更改。这就是pthread_cond_wait释放它的原因。不,该功能最终不会释放,仅限于功能被阻止的时间段。现在我们的通知线程可以更改并向pthread_cond_wait发送信号,表明发生了一些事情。 当pthread_cond_wait取消阻止(返回)时,互斥锁会再次被锁定!

void* notifying(void* arg)
{
  pthread_mutex_lock(&mutex);
  value = 1;
  pthread_cond_signal(&cond);
  pthread_mutex_unlock(&mutex);
}

有趣的是,通常在循环中等待条件变量,一次又一次地检查条件。为什么?有时pthread_cond_wait会在没有从通知函数获取信号的情况下解锁(所谓的杂散信号)。