使用条件变量(C,GCC)时出乎意料的行为



我正在尝试学习如何在C中正确使用条件变量。作为我自己的练习,我正在尝试制作一个小程序,其中有两个线程在无尽的环中打印" ping",然后是" pong"。

我写了一个小程序:

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void* T1(){
    printf("thread 1 startedn");
    while(1)
    {
        pthread_mutex_lock(&lock);
        sleep(0.5);
        printf("pingn");
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&lock);
        pthread_cond_wait(&cond,&lock);
    }
}
void* T2(){
    printf("thread 2 startedn");
    while(1)
    {
        pthread_cond_wait(&cond,&lock);
        pthread_mutex_lock(&lock);
        sleep(0.5);
        printf("pongn");
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&lock);
    }
}
int main(void)
{
    int i = 1;
    pthread_t t1;
    pthread_t t2;

    printf("mainn");
    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

任何想法该程序不预期执行的原因是什么?

预先感谢。

sleep采用整数,而不是浮点。不确定sleep(0)在您的系统上做什么,但这可能是您的问题之一。

您需要在调用pthread_cond_wait时握住Mutex。

裸露的条件变量(这是条件变量,没有表明在其他地方有读取的条件(几乎总是错误的。条件变量表明我们正在等待的东西可能已经准备好被消耗,它们不是用于信号的(不是因为它是非法的,而是因为很难让它们正确的纯信号传递(。因此,总的来说,条件会如下所示:

 /* 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);

拿着锁时睡觉是个坏主意。

T1T2不是用作pthread_create功能的有效功能,它们应该进行参数。做对了。

您在cond_signal和cond_wait之间都在每个线程中赛车,因此每个线程可能一直自称自身发出信号是不可能的。(正确地将Mutex握在pthread_cond_wait的电话中可能会有所帮助,或者可能没有帮助,这就是为什么我说正确的变量很难,因为它很难(。

首先,您永远不要使用sleep((同步线程(如果需要降低输出速度,请使用nanosleep()(。您可能需要(常用(共享变量ready,以便每个线程都知道他可以打印消息。在制作pthread_cond_wait()之前,必须获得锁定,因为 pthread_cond_wait((函数应在条件变量上阻止。它应以呼叫线或未定义的行为结果锁定的穆特克斯来调用。

步骤是:

  1. 获取锁
  2. 在Guard [*]
  3. 中使用共享变量,请使用等待一段时间
  4. 做事
  5. 更改共享变量的值进行同步(如果您有一个(,并将完成工作的信号/广播
  6. 释放锁

步骤4和5可以逆转。

[*] 您使用 pthread_cond_wait()释放互斥品并阻止条件变量上的线程,当使用条件变量时,总有一个布尔谓词,涉及与每个条件相关的共享变量等待,如果线程应为true,则继续进行,因为可能会发生虚假的唤醒。在这里观看更多

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int ready = 0;
void* T1(){
    printf("thread 1 startedn");
    while(1)
    {
        pthread_mutex_lock(&lock);
        while(ready == 1){
            pthread_cond_wait(&cond,&lock);
        }
        printf("pingn");
        ready = 1;
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&lock);
    }
}
void* T2(){
    printf("thread 2 startedn");
    while(1)
    {
        pthread_mutex_lock(&lock);
        while(ready == 0){
            pthread_cond_wait(&cond,&lock);
        }
        printf("pongn");
        ready = 0;
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&lock);
    }
}
int main(void)
{
    int i = 1;
    pthread_t t1;
    pthread_t t2;

    printf("mainn");
    pthread_create(&t1,NULL,&T1,NULL);
    pthread_create(&t2,NULL,&T2,NULL);
    pthread_join(t1,NULL);
    pthread_join(t2,NULL);
    return EXIT_SUCCESS;
}

您还应在main中使用pthread_join(),而不是while(1)

最新更新