9

我正在尝试实现pthread_cond_wait2 个线程。我的测试代码试图使用两个线程来执行以下场景:

  • 线程 B 等待条件
  • 线程 A 打印了五次“Hello”
  • 线程 A 向线程 B 发出信号
  • 线程 A 等待
  • 线程 B 打印“再见”
  • 线程 B 向线程 A 发出信号
  • 循环开始 (x5)

到目前为止,代码打印了五次“Hello”然后卡住了。从我看过的例子来看,我似乎走在正确的轨道上,“锁定互斥锁,等待,由其他线程发出信号,解锁互斥锁,做事,循环”

测试代码:

//Import 
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

//global variables
pthread_cond_t      condA  = PTHREAD_COND_INITIALIZER;
pthread_cond_t      condB  = PTHREAD_COND_INITIALIZER;
pthread_mutex_t     mutex = PTHREAD_MUTEX_INITIALIZER;




void *threadA()
{
    int i = 0, rValue, loopNum;

    while(i<5)
    {
        //unlock mutex
        rValue = pthread_mutex_unlock(&mutex);

        //do stuff
        for(loopNum = 1; loopNum <= 5; loopNum++)
            printf("Hello %d\n", loopNum);

        //signal condition of thread b
        rValue = pthread_cond_signal(&condB);

        //lock mutex
        rValue = pthread_mutex_lock(&mutex);

        //wait for turn
        while( pthread_cond_wait(&condA, &mutex) != 0 )

        i++;
    }

}



void *threadB()
{
    int n = 0, rValue;

    while(n<5)
    {
        //lock mutex
        rValue = pthread_mutex_lock(&mutex);

        //wait for turn
        while( pthread_cond_wait(&condB, &mutex) != 0 )

        //unlock mutex
        rValue = pthread_mutex_unlock(&mutex);

        //do stuff
        printf("Goodbye");

        //signal condition a
        rValue = pthread_cond_signal(&condA);

        n++;        
    }
}




int main(int argc, char *argv[])
{
    //create our threads
    pthread_t a, b;

    pthread_create(&a, NULL, threadA, NULL);
    pthread_create(&b, NULL, threadB, NULL);

    pthread_join(a, NULL);
    pthread_join(b,NULL);
}

非常感谢您提供正确方向的指针,谢谢!(在 Linux 上使用“gcc timeTest.c -o timeTest -lpthread”编译的代码)

4

2 回答 2

29

你有两个问题。首先是您没有while()正确使用循环 - 例如,这里:

//wait for turn
while( pthread_cond_wait(&condA, &mutex) != 0 )

i++;

循环的主体while是语句i++- 这将执行pthread_cond_wait()i++直到pthread_cond_wait()返回错误,所以这本质上是一个无限循环。

第二个是您不能单独使用 pthreads 条件变量 - 它需要与一些实际的共享状态配对(最简单的,这个共享状态可能只是一个受互斥锁保护的标志变量)。该pthread_cond_wait()函数用于等待共享状态达到某个值,pthread_cond_signal()当线程改变了共享状态时使用该函数。修改您的示例以使用这样的变量:

//global variables
/* STATE_A = THREAD A runs next, STATE_B = THREAD B runs next */
enum { STATE_A, STATE_B } state = STATE_A;
pthread_cond_t      condA  = PTHREAD_COND_INITIALIZER;
pthread_cond_t      condB  = PTHREAD_COND_INITIALIZER;
pthread_mutex_t     mutex = PTHREAD_MUTEX_INITIALIZER;

void *threadA()
{
    int i = 0, rValue, loopNum;

    while(i<5)
    {
        /* Wait for state A */
        pthread_mutex_lock(&mutex);
        while (state != STATE_A)
            pthread_cond_wait(&condA, &mutex);
        pthread_mutex_unlock(&mutex);

        //do stuff
        for(loopNum = 1; loopNum <= 5; loopNum++)
            printf("Hello %d\n", loopNum);

        /* Set state to B and wake up thread B */
        pthread_mutex_lock(&mutex);
        state = STATE_B;
        pthread_cond_signal(&condB);
        pthread_mutex_unlock(&mutex);

        i++;
    }

    return 0;
}

void *threadB()
{
    int n = 0, rValue;

    while(n<5)
    {
        /* Wait for state B */
        pthread_mutex_lock(&mutex);
        while (state != STATE_B)
            pthread_cond_wait(&condB, &mutex);
        pthread_mutex_unlock(&mutex);

        //do stuff
        printf("Goodbye\n");

        /* Set state to A and wake up thread A */
        pthread_mutex_lock(&mutex);
        state = STATE_A;
        pthread_cond_signal(&condA);
        pthread_mutex_unlock(&mutex);

        n++;
    }

    return 0;
}

请注意,这里不需要使用两个条件变量condAcondB- 如果只使用一个条件变量,代码将同样正确。

于 2012-12-03T00:31:34.903 回答
0

当您将花括号添加到 while 循环时,该代码实际上在我的机器上几乎可以正常工作。

除了 caf 所说的,在 threadA 已经发送 condB 信号后启动 threadB 时,您将进入无限循环,因此为什么需要在 while 循环中使用共享状态。

您可以使用第 47 行引入人为延迟usleep(1)并亲自查看。

于 2017-03-25T20:08:44.417 回答