为什么此代码 return 出乎意料的结果? (条件变量)
why this code return unexpected result? (conditional variable)
正在研究互斥锁
所以,我写了关于互斥锁的测试代码。
但是这段代码有问题。
我要展示:
downloading.....
complete....
start play!
但在运行时,结果是:
downloading.....
complete....
我不知道
1.为什么这段代码有错误?
2. 如何修复此代码?
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int buffer = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void* download(void *arg){
printf("downloading.....\n");
pthread_mutex_lock(&lock);
sleep(3);
buffer = 10;
printf("complete....\n");
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
return NULL;
}
void* play(void *arg){
pthread_mutex_lock(&lock);
pthread_cond_wait(&cond, &lock);
printf("start play!\n");
--buffer;
pthread_mutex_unlock(&lock);
return NULL;
}
int main(){
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, play, NULL);
pthread_create(&tid2, NULL, download, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
}
download()
函数恰好运行首先获取互斥量并完成其所有工作(包括在释放互斥量之前调用pthread-cond_signal()
。
play()
线程在发送信号之前没有机会调用pthread_cond_wait()
,因为download()
刚好先获取了互斥量。所以当play()
有机会等待时,它已经错过了唤醒它的信号。
解决方法是将条件变量与标志结合使用(可能 buffer
- 取决于您实际想要做什么)。 flag 需要做几件事:
- 在调用
pthread_cond_wait()
之前必须检查标志,如果标志表明条件已经满足,则应 不 等待
- "check flag/wait only if condition is not met yet" 操作应该在循环中执行,因为
pthread_cond_wait()
可以 return 虚假地(即,没有发出信号)
- 标志检查 和 对标志的任何更新(在任何线程中)都必须在持有互斥锁的同时完成
类似于(以下代码未经测试):
void* play(void *arg)
{
pthread_mutex_lock(&lock);
while (buffer < 1) {
pthread_cond_wait(&cond, &lock);
}
printf("start play!\n");
--buffer;
pthread_mutex_unlock(&lock);
return NULL;
}
正在研究互斥锁
所以,我写了关于互斥锁的测试代码。
但是这段代码有问题。
我要展示:
downloading.....
complete....
start play!
但在运行时,结果是:
downloading.....
complete....
我不知道 1.为什么这段代码有错误? 2. 如何修复此代码?
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int buffer = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void* download(void *arg){
printf("downloading.....\n");
pthread_mutex_lock(&lock);
sleep(3);
buffer = 10;
printf("complete....\n");
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
return NULL;
}
void* play(void *arg){
pthread_mutex_lock(&lock);
pthread_cond_wait(&cond, &lock);
printf("start play!\n");
--buffer;
pthread_mutex_unlock(&lock);
return NULL;
}
int main(){
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, play, NULL);
pthread_create(&tid2, NULL, download, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
}
download()
函数恰好运行首先获取互斥量并完成其所有工作(包括在释放互斥量之前调用pthread-cond_signal()
。
play()
线程在发送信号之前没有机会调用pthread_cond_wait()
,因为download()
刚好先获取了互斥量。所以当play()
有机会等待时,它已经错过了唤醒它的信号。
解决方法是将条件变量与标志结合使用(可能 buffer
- 取决于您实际想要做什么)。 flag 需要做几件事:
- 在调用
pthread_cond_wait()
之前必须检查标志,如果标志表明条件已经满足,则应 不 等待 - "check flag/wait only if condition is not met yet" 操作应该在循环中执行,因为
pthread_cond_wait()
可以 return 虚假地(即,没有发出信号) - 标志检查 和 对标志的任何更新(在任何线程中)都必须在持有互斥锁的同时完成
类似于(以下代码未经测试):
void* play(void *arg)
{
pthread_mutex_lock(&lock);
while (buffer < 1) {
pthread_cond_wait(&cond, &lock);
}
printf("start play!\n");
--buffer;
pthread_mutex_unlock(&lock);
return NULL;
}