我正在尝试学习如何在C中正确使用条件变量。 作为一个练习我自己,我试图用2个线程打印一个小程序,打印" Ping"其次是" Pong"在一个无限循环中。
我写了一个小程序:
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void* T1(){
printf("thread 1 started\n");
while(1)
{
pthread_mutex_lock(&lock);
sleep(0.5);
printf("ping\n");
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
pthread_cond_wait(&cond,&lock);
}
}
void* T2(){
printf("thread 2 started\n");
while(1)
{
pthread_cond_wait(&cond,&lock);
pthread_mutex_lock(&lock);
sleep(0.5);
printf("pong\n");
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
}
int main(void)
{
int i = 1;
pthread_t t1;
pthread_t t2;
printf("main\n");
pthread_create(&t1,NULL,&T1,NULL);
pthread_create(&t2,NULL,&T2,NULL);
while(1){
sleep(1);
i++;
}
return EXIT_SUCCESS;
}
运行此程序时,我得到的输出是:
main
thread 1 started
thread 2 started
ping
知道程序没有按预期执行的原因是什么?
提前致谢。
答案 0 :(得分:2)
sleep
采用整数,而不是浮点数。不确定sleep(0)
在您的系统上做了什么,但这可能是您遇到的问题之一。
您需要在调用pthread_cond_wait
时按住互斥锁。
裸条件变量(即条件变量不表示存在读取其他地方的条件)几乎总是错误的。一个条件变量表明我们正在等待的东西可能已经准备好被消费,它们不是用于信令(不是因为它是非法的,而是因为它很难让它们适合纯信令)。所以通常条件如下:
/* consumer here */
pthread_mutex_lock(&something_mutex);
while (something == 0) {
pthread_cond_wait(&something_cond, &something_mutex);
}
consume(something);
pthread_mutex_unlock(&something_mutex);
/* ... */
/* producer here. */
pthread_mutex_lock(&something_mutex);
something = 4711;
pthread_cond_signal(&something_cond, &something_mutex);
pthread_mutex_unlock(&something_mutex);
在握住锁的同时入睡是一个坏主意。
T1
和T2
不是用作pthread_create
函数的有效函数,它们应该接受参数。做得对。
你在cond_signal和cond_wait之间的每个线程中竞争自己,所以每个线程可能只是一直发出信号并不难以置信。 (在pthread_cond_wait的调用中正确地保持互斥体可能对此有所帮助,或者可能没有,这就是为什么我说正确获取裸条件变量很难,因为它是。)
答案 1 :(得分:1)
首先,你永远不应该使用sleep()来同步线程(如果需要降低输出速度,请使用nanosleep()
)。您可能需要(这是一个常见用途)共享变量ready
,让每个线程都知道他可以打印消息。在创建pthread_cond_wait()
之前,必须获取锁,因为 pthread_cond_wait()函数将阻塞条件变量。它应该被调用线程锁定的互斥锁或未定义的行为结果调用。
步骤是:
步骤4和5可以颠倒。
[*] 使用pthread_cond_wait()
释放互斥锁并阻塞条件变量上的线程,当使用条件变量时,总会有一个布尔谓词,涉及与每个条件等待关联的共享变量如果线程应该继续,因为可能会发生虚假的唤醒。 watch more here
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int ready = 0;
void* T1(){
printf("thread 1 started\n");
while(1)
{
pthread_mutex_lock(&lock);
while(ready == 1){
pthread_cond_wait(&cond,&lock);
}
printf("ping\n");
ready = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
}
void* T2(){
printf("thread 2 started\n");
while(1)
{
pthread_mutex_lock(&lock);
while(ready == 0){
pthread_cond_wait(&cond,&lock);
}
printf("pong\n");
ready = 0;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
}
int main(void)
{
int i = 1;
pthread_t t1;
pthread_t t2;
printf("main\n");
pthread_create(&t1,NULL,&T1,NULL);
pthread_create(&t2,NULL,&T2,NULL);
pthread_join(t1,NULL);
pthread_join(t2,NULL);
return EXIT_SUCCESS;
}
您还应该使用pthread_join()
中的main
代替while(1)