为什么pthread条件变量被绞死?

时间:2015-03-25 16:14:38

标签: c++ pthreads condition-variable

我刚开始学习pthread条件变量。但是下面的代码没有按预期工作。

#include<iostream>
#include<pthread.h>

using namespace std;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t count_threshold_cv = PTHREAD_COND_INITIALIZER;
int count=0;


void *inc_func(void *arg)
{
    pthread_mutex_lock(&mutex);
    int c;

    while(1)
    {
        cin>>c;
        if(c==8){ 
            pthread_cond_signal(&count_threshold_cv);break;}
    }

    cout<<"inc count reached 8"<<endl;
    pthread_mutex_unlock(&mutex);

}

void *watch(void *arg)
{
    pthread_mutex_lock(&mutex);
    while(1){
        pthread_cond_wait(&count_threshold_cv,&mutex);
        break;
    }
    cout<<"This executed"<<endl;
    pthread_mutex_unlock(&mutex);
}

int main()
{
    pthread_t id[26];
    pthread_create(&id[0],NULL,inc_func,NULL);
    pthread_create(&id[1],NULL,watch,NULL);

    int i;
    for(i=0;i<2;i++)
    {
        pthread_join(id[i],NULL);
    }

}

当输入为8时,此代码被挂起&#34; inc计数达到8?我无法理解。  我的理解在哪里错了?

3 个答案:

答案 0 :(得分:3)

正确的解决办法是让watch线程只等待它等待的条件还没有发生。

条件似乎是c == 8(因为这是发出信号的信号),因此您需要将c变量设为全局,以便在线程之间共享,然后更改{{ 1}}线程要做:

watch

现在首先运行哪个线程并不重要:您的代码无论哪种方式都是正确的。这是使用条件变量的正确方法:通常,服务员应该这样做:

void *watch(void *arg)
{
    pthread_mutex_lock(&mutex);
    while (c != 8) {
        pthread_cond_wait(&count_threshold_cv, &mutex);
    }
    cout<<"This executed"<<endl;
    pthread_mutex_unlock(&mutex);

    return 0;
}

并且信号员应该这样做:

pthread_mutex_lock(&mutex);

while (!condition)
    pthread_cond_wait(&cond, &mutex);

/* ... */

答案 1 :(得分:2)

这里重要的是pthread_cond_signal将取消阻止该条件变量上阻塞的至少一个线程(意味着在同一条件变量上调用pthread_cond_wait时当前被阻塞的线程) 。如果在一个线程调用pthread_cond_signal时,没有其他线程等待该条件,那么基本上没有任何事情发生。

记住这一点,你的程序流程是这样的:

  • 创建并启动第一个帖子;
  • 第一个线程调用inc_func(),它先锁定互斥锁;
  • inc_func()一直等待输入数字8,保持互斥锁始终锁定;
  • 在此期间的某个时间,但大部分时间可能在inc_func设法锁定互斥锁后,第二个线程被创建;
  • 第二个线程也试图在函数开始时锁定互斥锁,并因为第一个线程已将其锁定而被阻止;
  • 在某些时候,您输入8并且条件从线程1发出信号; 线程2还没有等待这个条件,所以它仍然被阻止试图锁定互斥锁;
  • 第一个线程最终释放互斥锁,因此线程2将其锁定,然后在pthread_cond_wait上阻塞。

此时,线程1已经完成,线程2被阻塞等待条件被发出信号,主线程正在等待它完成。没有其他人可以发出这种情况的信号,所以你有一个悬念。

对于可能大部分时间 的快速修复,您可以尝试更改启动线程的顺序(启动watch首先是线程)。但请记住并理解为什么我在可能大多数时候使用粗体。 解决这个问题的正确方法是重新考虑你的锁定策略:在尽可能小的范围内锁定互斥锁,并在最短的时间内锁定它们。

答案 2 :(得分:1)

交换线程的执行顺序:

pthread_create(&id[1],NULL,watch,NULL);
pthread_create(&id[0],NULL,inc_func,NULL);

如果您首先运行thread0,则thread1永远不会超过互斥锁,因此它不会开始等待。比thread0结束,只有thread1执行pthread_cond_wait(),但没有线程要做signal

如果您先启动thread1,它会转到等待部分。