条件变量和mutex_unlock

时间:2015-03-28 17:54:12

标签: c pthreads mutex condition-variable

代码:

void *inc_func(void *arg)
{
    pthread_mutex_lock(&mutex);
    pthread_cond_signal(&count_threshold_cv);
    sleep(1);
    pthread_mutex_unlock(&mutex);
}
void *watch(void *arg)
{
    pthread_mutex_lock(&mutex);
    pthread_cond_wait(&count_threshold_cv,&mutex);
    sleep(1);
    pthread_mutex_unlock(&mutex);
}
int main()
{
    pthread_t id[2];
    pthread_create(&id[0],NULL,watch,NULL);
    pthread_create(&id[1],NULL,inc_func,NULL);
    int i;
    for(i=0;i<2;i++)
        pthread_join(id[i],NULL);
}

现在我们在每个线程中都有一个mutex_unlock函数。还有一个锁定的互斥锁。为什么这不会导致undefined behaviour。由于两个线程都试图解锁相同的互斥锁,导致一个互联网尝试解锁已经解锁的互斥锁。

编辑:pthread_cond_wait释放要使用的第二个线程的mutex。现在考虑第二个线程执行pthread_cond_signal,这导致第一个线程重新获取mutex。现在我们有两个具有相同mutex锁的线程,因为两个线程都没有因为'sleep'函数而执行mutex_unlock。我的理解错了吗?

2 个答案:

答案 0 :(得分:1)

    如果要锁定的互斥锁已被锁定,则
  • pthread_mutex_lock()会阻止。如果互斥锁解锁则返回。

  • pthread_cond_wait()在开始等待时解锁互斥锁,并在返回之前解锁。如果相关的互斥锁仍然被锁定,则返回可能会延迟。然后返回将延迟,直到互斥锁解锁。

将上述内容放在一起并将其应用到您显示的代码中,可以看到每个线程函数都以锁定后跟解锁(等等)开始,所以一切都很好。

参考示例代码:pthread_cond_wait()inc_func()调用pthread_mutex_unlock()时返回。


要成功处理示例代码描述的场景,您需要考虑两种特殊情况

  1. 信号首先出现的情况
  2. 所谓"spurious wake-ups"的情况,即pthread_cond_wait()在没有发出信号的情况下返回。
  3. 要处理这两种情况,每个条件都应该有一个监视变量。

    pthread_mutex_t mutex = ...
    pthread_cond_t count_threshold_cv = ...
    
    int signalled = 0;
    
    void *inc_func(void *arg)   
    {
      pthread_mutex_lock(&mutex);
    
      pthread_cond_signal(&count_threshold_cv);
      signalled = 1;
    
      pthread_mutex_unlock(&mutex);  
    }
    
    void *watch(void *arg)
    {
      pthread_mutex_lock(&mutex);
    
      while (0 == signalled)
      {
        pthread_cond_wait(&count_threshold_cv,&mutex);
      }
    
      pthread_mutex_unlock(&mutex);
    }
    
    int main(void)
    {
      pthread_t id[2];
      pthread_create(&id[0],NULL,watch,NULL);
      pthread_create(&id[1],NULL,inc_func,NULL);
      int i;
      for(i=0;i<2;i++)
        pthread_join(id[i],NULL);
    }  
    

答案 1 :(得分:1)

如果订单确实是

  • watch先运行并锁定(inc_func等待)
  • 具有互斥锁的{li> watch使用pthread_cond_wait等待解锁互斥文件并根据documentation 进行阻止
  

这些函数以原子方式释放互斥锁并导致调用线程   在条件变量cond上阻止;

这允许以下

  • inc_func获取互斥锁然后发出信号(此时互斥锁尚未释放)
  • inc_func发布互斥锁
  • 由于互斥锁已被释放且互斥锁已解锁执行已根据documentation锁定互斥锁的watch个简历:
  

成功返回后,互斥锁已被锁定,并由调用线程拥有。

  • 以下是互斥锁的合法发布。

如果inc_func的代码首先执行而未切换到watch

,那么您未考虑的方案是什么?
  • inc_func锁定互斥锁
  • inc_func信号,但没有人发出信号,这没关系。
  • inc_func解锁互斥锁
  • watch锁定互斥锁
  • 然后等待条件变量但是没有人发信号所以它会永远等待。