1

最近、私は pthread マルチスレッド ライブラリを調査し、いくつかの例を実行しています。

Producer-Customer モジュールを作成しようとしています。Producer の製品を格納するためのキューがあり、Customer が取得できます。

キューの MAX-SIZE を 20 に設定しました。キューがいっぱいになると、Customer スレッドが 1 つを消費し、生産を開始できる Producer スレッドがなくなるまで、Producer スレッドは待機します。Customer と同じように、キューが空の場合、Customer は Producer スレッドが新しいスレッドを生成して通知するまで待機します。:-)

Customer スレッドを生成よりも速く消費するように設定しました。しかし、Producer スレッドの消費を消費よりも速く設定すると、ついにデッドロックが発生するようです:-(

理由がわかりません。誰か親切に私のコードを読んで、ヒントやコードの変更方法を教えてもらえますか?

ありがとう!

#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;
}
4

1 に答える 1

0

あなたの生産者はあなたの消費者と同じ条件で待っていますか? これは間違いなくトラブルの元です。コードを概念的に考えてください。プロデューサーが「プロデュース」する前に必要な前提条件は何ですか? あなたが述べたように、バッファにはスペースが必要です。

詳しくは調べませんでしたが、プロデューサーが使用する追加の条件変数が必要になる可能性があります (コンシューマーとは異なります)。プロデューサーは、キューがいっぱいの場合にのみ待機します。コンシューマーは、キューから何かを正常に取得するたびにシグナルを送信します。

編集: pthread lib のドキュメントを読むと、1 つのミューテックスを 2 つの条件で使用できます

疑似コードのアイデア:)

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

できれば、ロックしたときに信号を送ってください。ここでは、順序に違いはないと思います。

于 2013-03-28T11:23:38.977 に答える