我正在用 C 语言编写一个使用 pthread 的生产者-消费者程序。该程序应该生产和消费最多达到限制 n 的项目。然而,当 n = 1 和 n = 2 时,我的程序通常很快就会卡住。 更具体地说,“卡住”意味着它停止打印任何“(”或“)”。程序需要手动退出。
这是我的代码。
#include "thread.h"
#include <semaphore.h>
int n, count = 0;
pthread_mutex_t lk = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
void Tproduce(){
while(1){
pthread_mutex_lock(&lk);
while(count == n){
pthread_cond_wait(&cv,&lk);
}
assert(count != n);
printf("(");
count++;
//printf("%d\t", count);
pthread_cond_signal(&cv);
pthread_mutex_unlock(&lk);
}
}
void Tconsume(){
while(1){
pthread_mutex_lock(&lk);
while(count == 0){
pthread_cond_wait(&cv,&lk);
}
assert(count != 0);
printf(")");
count--;
//printf("%d\t",count);
pthread_cond_signal(&cv);
pthread_mutex_unlock(&lk);
}
}
int main(int argc, char* argv[]){
assert(argc==2);
n=atoi(argv[1]);
setbuf(stdout,NULL);
for(int i = 0; i < 8; i++){
create(Tproduce);
create(Tconsume);
}
}
create
这里只是简单的在自制的线程池中创建一个线程,经测试工作正常。
我尝试使用 pthread_cond_broadcast 或使用两个条件变量,两种方法都工作正常。但是,我不明白为什么在使用 pthread_cond_signal 时程序会卡住。
至少应该有一个线程正常工作,并且所有被阻塞的线程都应该有机会被唤醒。即使生产者线程或消费者线程被错误唤醒并尝试获取锁,它们也应该与以前从未获取过 futex 锁的线程竞争。由于这些错误唤醒的线程不满足条件,因此它们将释放锁,从而允许外部线程(那些从未获取过 futex 锁的线程)获取它。
因此,在最坏的情况下,以生产者为例,消费者线程无论是阻塞在futex锁上还是条件变量上,都应该总有机会被调用,不应该完全卡住。
我正在 WSL2、ubuntu 20 中运行此代码,如果有帮助的话。
我将非常感谢任何想法或解决方案。
您的程序因以下原因而卡住:
n 和 count 在程序启动时均为零。
Tproduce
进入等待循环,等待 count 不再等于 n 0。由于 n 和 count 都初始化为零,因此该线程实际上正在等待另一个线程更改这些变量之一:
while(count == n){
pthread_cond_wait(&cv,&lk);
}
Tconsume
首先进入类似的循环。等待计数不为零: while(count == 0){
pthread_cond_wait(&cv,&lk);
}
因此两个线程都卡在各自的
pthread_cond_wait
调用上。死锁是因为没有任何东西会增加count
,也没有任何东西可以唤醒任何一个线程。