Multithreading 多线程死锁-使用pthread lib的生产者和消费者模块

Multithreading 多线程死锁-使用pthread lib的生产者和消费者模块,multithreading,pthreads,deadlock,Multithreading,Pthreads,Deadlock,最近我正在研究pthread多线程库并做一些示例 我尝试编写一个生产者-客户模块:有一个队列来存储生产者的产品,并且可以由客户获取 我将队列最大大小设置为20。当队列已满时,生产者线程将等待,直到客户线程消费了一个队列,并且不适合他可以开始生产的生产者线程。与客户一样,当队列为空时,客户将等待生产者线程生成新线程并通知他:- 我将客户线程设置为消费快于生产,它可以很好地作为日志输出,这与我的预期相符。但是,当我将生产者线程的消耗设置为快于消耗时,似乎最终导致了死锁:- 我不知道原因,谁能读一下我

最近我正在研究pthread多线程库并做一些示例

我尝试编写一个生产者-客户模块:有一个队列来存储生产者的产品,并且可以由客户获取

我将队列最大大小设置为20。当队列已满时,生产者线程将等待,直到客户线程消费了一个队列,并且不适合他可以开始生产的生产者线程。与客户一样,当队列为空时,客户将等待生产者线程生成新线程并通知他:-

我将客户线程设置为消费快于生产,它可以很好地作为日志输出,这与我的预期相符。但是,当我将生产者线程的消耗设置为快于消耗时,似乎最终导致了死锁:-

我不知道原因,谁能读一下我的代码,给我一些提示或者如何修改代码

谢谢

#include "commons.h"

typedef struct tagNode {
    struct tagNode *pNext;
    char *pContent;
}NodeSt, *PNodeSt;

typedef struct {
    size_t  mNodeNum;
    size_t  mNodeIdx;
    PNodeSt mRootNode;
}WorkQueue;

#define WORK_QUEUE_MAX 20

static pthread_cond_t  g_adder_cond  = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t g_adder_mutex = PTHREAD_MUTEX_INITIALIZER;
static WorkQueue g_work_queue = {0};
//------------------------------------------------------------------------
void *customer_thread_runFunc(void *usrdat){
    for( ; ; ) {
pthread_mutex_lock(&g_adder_mutex);{
        while( g_work_queue.mNodeNum == 0 ) {
            pthread_cond_wait(&g_adder_cond, &g_adder_mutex);
        }
/********************** CONSUME NEW PRODUCT ***********************/
        g_work_queue.mNodeNum --;

        if( g_work_queue.mRootNode->pNext != NULL ) {
            PNodeSt pTempNode = g_work_queue.mRootNode->pNext;
            free( g_work_queue.mRootNode->pContent );
            free( g_work_queue.mRootNode );
            g_work_queue.mRootNode = pTempNode;
        } else {
            free( g_work_queue.mRootNode->pContent );
            free( g_work_queue.mRootNode );
            g_work_queue.mRootNode = NULL;
        }
/********************** CONSUME PRODUCT END ***********************/
        // Nofity Producer Thread
        pthread_cond_signal(&g_adder_cond);
}pthread_mutex_unlock(&g_adder_mutex);

        // PAUSE FOR 300ms
        usleep(300); 
    }
    return NULL;
}
//------------------------------------------------------------------------
void *productor_thread_runFunc( void *usrdat ) {
    for( ; ; ) {
pthread_mutex_lock(&g_adder_mutex); {
        char tempStr[64];
        PNodeSt pNodeSt = g_work_queue.mRootNode;

        while( g_work_queue.mNodeNum >= WORK_QUEUE_MAX ) {
            pthread_cond_wait(&g_adder_cond, &g_adder_mutex);
        }

/********************** PRODUCE NEW PRODUCT ***********************/
        g_work_queue.mNodeNum ++;
        g_work_queue.mNodeIdx ++;

        if( pNodeSt != NULL ) {
            for( ; pNodeSt->pNext != NULL; pNodeSt = pNodeSt->pNext );
            pNodeSt->pNext = malloc(sizeof(NodeSt));
            memset(pNodeSt->pNext, 0, sizeof(NodeSt));
            sprintf( tempStr, "production id: %d", g_work_queue.mNodeIdx);
            pNodeSt->pNext->pContent = strdup(tempStr);
        } else {
            g_work_queue.mRootNode = malloc(sizeof(NodeSt));
            memset(g_work_queue.mRootNode, 0, sizeof(NodeSt));
            sprintf( tempStr, "production id: %d", g_work_queue.mNodeIdx);
            g_work_queue.mRootNode->pContent = strdup(tempStr);
        }
/********************** PRODUCE PRODUCT END ***********************/
        // Nofity Customer Thread
        pthread_cond_signal(&g_adder_cond);
}pthread_mutex_unlock(&g_adder_mutex);

        // PAUSE FOR 150ms, faster than Customer Thread
        usleep(150); 
    }
    return NULL;
}
//------------------------------------------------------------------------
int main(void) {

    pthread_t pt1, pt3;
    pthread_attr_t attr;

    pthread_attr_init(&attr);
    pthread_create(&pt1, &attr, customer_thread_runFunc, NULL);
    pthread_create(&pt3, &attr, productor_thread_runFunc, NULL);
    pthread_join(pt1, NULL);
    pthread_join(pt3, NULL);

    printf("MAIN - main thread finish!\n");
    return EXIT_SUCCESS;
}

您的生产商和您的消费者在等待相同的条件?这绝对是麻烦的根源。从概念上考虑您的代码。生产商在生产前需要哪些先决条件?正如您提到的,缓冲区需要有空间

我没有详细介绍,但是您可能需要一个额外的条件变量,它由生产者使用,与消费者使用的不同。生产者仅在队列已满时等待。每次从队列中成功检索某个内容时,使用者都会发出信号

编辑:读取pthread lib的文档,一个互斥可以被两个条件使用

伪代码的概念:

Mutex mqueue
Condition cprod, ccons

produce()
  mqueue.lock
  while the queue is full
     cprod.wait(mqueue)
  end
  do the production on queue
  mcons.signal
  mqueue.unlock
end produce

consume()
  mqueue.lock
  while the queue is empty
      ccons.wait(mqueue)
  end
  do the consumption on the queue
  cprod.signal
  mqueue.unlock
end consume

最好在你有锁的时候发信号。在这里,我不认为顺序有什么区别。

它们可能在相同的条件下阻塞,但对于生产者来说,这意味着它已经至少向使用者线程发送了WORK\u QUEUE\u MAX通知,让它知道它可以继续working@LefterisE实际上,它们可以使用相同的锁,但不能在相同条件下阻塞。这根本没有道理。QUEUE EMPTY只对消费者有意义,QUEUE FULL只对生产者有意义。谢谢你,UmNyobe,我已经尝试使用双重条件来重新编写我的程序。但恐怕还是不行。最终还是会导致僵局。