带条件变量的Pthread同步

时间:2018-11-01 00:58:38

标签: c multithreading operating-system synchronization

我正在通过使用互斥对象和条件变量来练习有关pthread同步。在下面的代码中,我创建了3个线程,并且期望看到输出告诉执行了哪个线程,然后从主线程退出,报告了count的值。但是,我观察到可以有3种不同的输出。 这是我的代码:

#include<stdio.h> 
#include<string.h> 
#include<pthread.h> 
#include<stdlib.h> 
#include<unistd.h> 


typedef struct node{

    int data;
    struct node* next;

}LinkList;

LinkList *list = NULL ;
//LinkList *head;
int count;
int enter;

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

void* trythis(void *arg) 
{ 
    pthread_mutex_lock(&lock);
    //enter = 0;
    printf("Thread sleeps... \n");
    while(!enter){
        pthread_cond_wait(&cond,&lock);
    }
    enter = 1;
    printf("Thread %d Enter = %d\n",count++,enter);
    pthread_cond_signal(&cond);


    pthread_mutex_unlock(&lock);

    return NULL; 
} 

int main(int argc, char** argv){

    pthread_t tid[3];
    int error;
    int i = 0;
    printf("Main Beginning1\n");
    int p = pthread_mutex_init(&lock,NULL);

    if(p != 0){
        printf("Mutex failed \n");
        exit(1);
    }
    printf("Main Beginning2\n");
    while(i < 3) 
    { 
        error = pthread_create(&(tid[i]), NULL, &trythis, NULL); 
        if (error != 0) 
            printf("\nThread can't be created : [%s]", strerror(error)); 
        i++; 
    } 
    printf("Main Beginning3\n");
    /*for(int i = 0; i < 3; i++){
        pthread_join(tid[i], NULL); 
    }*/
    printf("Main Beginning4\n");
    pthread_mutex_lock(&lock);
    enter = 1;
    printf("Main Beginning\n");
    while(count < 2){

        pthread_cond_wait(&cond,&lock);
        printf("count : %d\n",count);
    }

    pthread_cond_signal(&cond);
    printf("Main count = %d\n",count);

    pthread_mutex_unlock(&lock);



    pthread_mutex_destroy(&lock);

    return 0;
}

我的输出是:

***FIRST OUTPUT***
oguzliv@oguzliv-VirtualBox:~/Desktop/OSindAir$ ./linklist 
Main Beginning1
Main Beginning2
Thread sleeps... 
Main Beginning3
Thread sleeps... 
Main Beginning4
Main Beginning
Thread sleeps... 
Thread 0 Enter = 1
Thread 1 Enter = 1
Thread 2 Enter = 1
count : 3
Main count = 3

***SECOND OUTPUT***
oguzliv@oguzliv-VirtualBox:~/Desktop/OSindAir$ ./linklist 
Main Beginning1
Main Beginning2
Thread sleeps... 
Main Beginning3
Main Beginning4
Main Beginning
Thread sleeps... 
Thread 0 Enter = 1
Thread sleeps... 
Thread 1 Enter = 1
count : 2
Main count = 2

***THIRD OUTPUT***
oguzliv@oguzliv-VirtualBox:~/Desktop/OSindAir$ ./linklist 
Main Beginning1
Main Beginning2
Thread sleeps... 
Thread sleeps... 
Main Beginning3
Main Beginning4
Thread sleeps... 
Main Beginning
(waits infinitely)

我不知道这些输出的原因。请帮我。顺便说一句,此代码独立于链接列表结构。

------编辑-----

经过一番研究,感谢此链接https://gist.github.com/rtv/4989304

的所有者,我按预期执行了代码

但是,我仍然对以前的代码感到困惑,为什么它不能作为已编辑的代码执行。所有更改为:

while(!enter){
        pthread_cond_wait(&cond,&lock);
    }
    enter = 1;
    printf("Thread %d Enter = %d\n",count++,enter);
    pthread_cond_signal(&cond);

const int myid = long(args);
printf("Thread sleeps with ID : %d\n",myid);
pthread_mutex_lock(&lock);
count++;
printf("Thread ID : %d count : %d",myid,count);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);

return NULL;

1 个答案:

答案 0 :(得分:0)

从根本上讲,您的原始代码正在为enter的价值而战。请考虑以下两种情况:

  1. 您的实现优先考虑新创建的线程。因此,一旦调用pthread_create(),trythis()就开始执行,获取互斥锁,发现!enter并等待cond发出信号。每个线程都会发生这种情况。然后主抓取互斥锁,将输入设置为1,然后等待cond发出信号。谁来唤醒他们?这种类型的同步失败曾经被称为阴谋诡计,但该术语已不再使用。
  2. 您的实现将运行线程优先。因此,pthread_create()构造了trythis(),但trythis尚未开始执行。当main完成创建线程后,它将获取互斥锁,将enter设置为1,然后等待cond发出信号。由于它正在等待(不再运行),因此其他线程启动,并且每个线程都抓住互斥锁,发现enter不为零,因此发出信号通知状态,删除互斥锁并退出。其中之一将唤醒main,因为它是唯一等待中的线程,当唤醒时,它发现count> 2,并按预期退出循环。

现实世界可以是这些的任意混合,因此您可能会发现留下0..3线程和/或main阻塞了。我认为答案是您的主行:

pthread_mutex_lock(&lock);
enter = 1;

应该添加:

pthread_cond_signal(&cond);

这样,已经在等待输入的任何人都将被释放。 从流程的角度来看; “ trythis”正在消耗输入,并产生计数; “主要”是生产输入和消耗计数。