为什么 pthread_condition 变量被挂起?

Why pthread_condition variable getting hanged?

刚开始学习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 时,此代码会在“inc count reached 8”处挂起?我无法理解。 我的理解哪里错了?

交换线程的执行顺序:

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

如果您 运行 thread0 作为第一个,thread1 永远不会超过互斥锁,因此它不会开始等待。比 thread0 结束,然后 thread1 执行 pthread_cond_wait(),但是没有线程可以做 signal.

如果你先开始thread1,它就会进入等待部分。

这里重要的是 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 线程)。但是请记住并理解为什么我 可能 大多数时候 使用粗体。 解决此问题的正确方法是重新考虑您的锁定策略:将互斥体锁定在尽可能小的范围内,并将它们锁定的时间尽可能短。

正确的解决方案是让 watch 线程仅在其等待的条件尚未发生时才等待。

条件似乎是 c == 8(因为这就是发出的信号),因此您需要将 c 变量设置为全局变量,以便它在线程之间共享,然后更改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);

/* ... */

信号员应该这样做:

pthread_mutex_lock(&mutex);

/* ... something that potentially makes condition true ... */

pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);