为什么我的使用 pthread_cond_signal 的生产者-消费者程序会卡住?

问题描述 投票:0回答:1

我正在用 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 中运行此代码,如果有帮助的话。

我将非常感谢任何想法或解决方案。

c producer-consumer condition-variable
1个回答
0
投票

您的程序因以下原因而卡住:

  • 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
,也没有任何东西可以唤醒任何一个线程。

© www.soinside.com 2019 - 2024. All rights reserved.