我正在尝试为2个线程实现pthread_cond_wait
。我的测试代码试图使用两个线程来执行以下场景:
到目前为止,代码打印“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);
}
非常感谢正确方向的指针,谢谢! (使用“gcc timeTest.c -o timeTest -lpthread”在Linux上编译的代码)
答案 0 :(得分:30)
你有两个问题。首先,您没有正确使用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;
}
请注意,这里不需要使用两个条件变量condA
和condB
- 如果只使用一个条件变量,代码就会正确。
答案 1 :(得分:0)
当您在while循环中添加大括号时,代码实际上在我的机器上几乎。
添加到caf所说的,当threadA已经发送condB信号后启动threadB时你将进入无限循环,因此你需要在while循环中使用共享状态。
您可以在第47行使用usleep(1)
介绍人工延迟,并亲眼看看。