为什么此代码 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;
}