为什么 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);
刚开始学习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);