Синхронизация Pthread с условными переменными - PullRequest
0 голосов
/ 01 ноября 2018

Я занимаюсь синхронизацией pthread с использованием мьютексов и условных переменных. В приведенном ниже коде я создаю 3 потока, и я ожидаю, что выходные данные будут сообщать о том, какой поток выполнен, а затем выходить из основного потока, сообщая значение счетчика. Однако я заметил, что у меня может быть 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)

Я не знаю причину этих выводов. Пожалуйста, помогите мне. Кстати, этот код не зависит от структуры списка ссылок.

------ EDIT -----

После некоторых исследований я выполнил код, как и ожидал, благодаря владельцу этой ссылки 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 голосов
/ 01 ноября 2018

По сути, ваш оригинальный код зависит от ввода. Рассмотрим два сценария:

  1. Ваша реализация отдает приоритет вновь созданным потокам. Итак, как только вызывается pthread_create (), trythis () начинает выполняться, захватывает мьютекс, обнаруживает! Enter и ожидает сигнала cond. Это происходит для каждого потока. Затем main захватывает мьютекс, устанавливает enter на 1, затем ждет, пока cond подаст сигнал. Кто их разбудит? Этот тип ошибки синхронизации раньше назывался интригой, но термин вышел из употребления.
  2. Ваша реализация отдает приоритет запущенному потоку. Итак, pthread_create () создает trythis (), но trythis еще не начинает выполняться. Когда main завершает создание потоков, он захватывает мьютекс, устанавливает enter в 1, а затем ожидает сигнала cond. Так как он ожидает (больше не работает), другие потоки запускаются, и каждый захватывает мьютекс, обнаруживает, что ввод не равен нулю, поэтому сигнализируйте условие, отбросьте мьютекс и выйдите. Один из них разбудит main, так как это единственный ожидающий поток, и когда он пробуждается, он обнаруживает, что count> 2, выходит из цикла, как и ожидалось.

Реальный мир может быть произвольной смесью, так что вы можете обнаружить, что вы оставили 0..3 темы и / или основной блок заблокированными. Ответ, я думаю, таков: ваша строка в основном:

pthread_mutex_lock(&lock);
enter = 1;

должен был добавить:

pthread_cond_signal(&cond);

Таким образом, любой, кто уже ждал при входе, будет освобожден. С точки зрения потока; «trythis» потребляет вход и производит подсчет; «main» производит ввод и потребление.

...