0

Я пытаюсь создать четыре потока, которые печатают какое-то сообщение.
У меня возникла проблема с синхронизацией.Планирование нескольких потоков с использованием Mutex и переменной условий

Вот что мой main() выглядит

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 
int count = 4; 

int main (void) 
{ 
    pthread_t thread1, thread2, thread3, thread4; 
    pthread_create (&thread4, NULL, function4, NULL); 
    pthread_create (&thread3, NULL, function3, NULL); 
    pthread_create (&thread2, NULL, function2, NULL); 
    pthread_create (&thread1, NULL, function1, NULL); 

    pthread_join (thread1, NULL); 
    pthread_join (thread2, NULL); 
    pthread_join (thread3, NULL); 
    pthread_join (thread4, NULL); 
    return 0;                 
} 

function1() отпечатков Function 1, function2() печатает Function 2 и так далее.

Желаемая выход должен быть следующим:

Function 1 
Function 2 
Function 3 
Function 4 

Фактический выход:

Function 1 
/* Infinitely runs (Deadlock maybe) */ 

Актуальна:
Можно ли использовать один переменной условия для синхронизации двух или более потоков? Если да, то как?

Если нет, то как решить эту проблему?


Вот это определение function(n)

void *function1() 
{ 
    while (1) 
    { 
    if (count == 4) 
     { 
      pthread_mutex_lock (&mutex); 
      printf("Function 1\n"); 
      count --; 
      pthread_mutex_unlock (&mutex); 
      pthread_cond_signal (&cond); 
      return NULL; 
     } 
     else 
      pthread_cond_wait(&cond, &mutex); 
    } 
    return NULL; 
} 

void *function2() 
{ 
while (1) 
    { 
     if (count == 3)               
     { 
      pthread_mutex_lock (&mutex); 
      printf("Function 2\n"); 
      count--; 
      pthread_mutex_unlock (&mutex); 
      pthread_cond_signal (&cond);           
      return NULL; 
     } 
     else                  
      pthread_cond_wait(&cond, &mutex);   
    } 
    return NULL; 
} 

void *function3() 
{ 
    while (1) 
    { 
     if(count == 2) 
     { 
      pthread_mutex_lock (&mutex); 
      printf("Function 3\n"); 
      count--; 
      pthread_mutex_unlock (&mutex); 
      pthread_cond_signal (&cond); 
      return NULL; 
     } 
     else 
      pthread_cond_wait(&cond, &mutex);  
    } 
    return NULL; 
} 

void *function4() 
{ 
    while (1) 
    { 
     if(count == 1) 
     { 
      pthread_mutex_lock (&mutex); 
      printf("Function 4\n"); 
      pthread_mutex_unlock (&mutex); 
      pthread_cond_signal (&cond); 
      return NULL; 
     } 
     else 
      pthread_cond_wait(&cond, &mutex); 
    } 
    return NULL; 
} 
+1

Обратите внимание, что вы должны использовать 'pthread_cond_wait', удерживая блокировку мьютекса. – juhist

ответ

0

После более четкого понимания, я решил эту проблему.
Это случай состояния гонки.

вещи неправильно с кодом:

  1. Использование pthread_cond_broadcast вместо pthread_cond_signal.
    Из man страниц

    pthread_cond_broadcast() функция разблокирует все темы, в настоящее время блокированы на заданное условие переменной конд.

    pthread_cond_signal() функция разблокирует по меньшей мере, один из потоков, которые заблокированы на указанном состоянии переменной конд

  2. Не приобретя lock перед проверкой if (count == X), нуждающемуся установить блокировку до этого (с count - глобальная/общая переменная).

  3. Не размещайте unlock, если элемент управления переходит на else. Поскольку замок уже размещен (ранее до else), вам необходимо unlock .

    Если вы этого не сделаете, другие потоки попытаются установить lock мьютексом, , который уже заблокирован, что приводит к условиям гонки.


Функция должна быть следовать

void *function1() 
{ 
    while (1) 
    { 
     /* Take a lock on the Mutex */ 
     pthread_mutex_lock (&mutex); 
     if (4 == count) 
     { 
      printf("Function 1\n"); /* Perform your task */ 
      count--; 
      /* Once operation on shared variable (count) is completed, release lock*/ 
      pthread_mutex_unlock (&mutex); 

      /* Broadcast to other threads about completion of task */ 
      pthread_cond_broadcast (&cond); 
      return NULL; 
     } 
     else 
     { 
      /* If count doesnt match, wait on the condition (wait for signal from other threads) */ 
      pthread_cond_wait(&cond, &mutex); 
      /* Unlock the mutex, since it was locked earlier - else goes to deadlock */ 
      pthread_mutex_unlock (&mutex); 
     } 
    } 
    return NULL; 
} 

Here полный рабочий код.

0

Изменение требуется просто:

вместо:

else 
    pthread_cond_wait(&cond, &mutex); 

сделать это:

else { 
    pthread_mutex_lock (&mutex); 
    pthread_cond_wait(&cond, &mutex); 
    pthread_mutex_unlock (&mutex); 
} 

Это работает для меня с этими изменениями, но приводит к непредсказуемому поведению без изменений.

Edit:

Это выше простой способ по-прежнему оставляет состояние гонки и не фиксирует signal против broadcast проблемы. Чтобы избежать этого, код должен быть структурирован как следующий:

pthread_mutex_lock (&mutex); 
if (count == 4) 
{ 
    printf("Function 1\n"); 
    count --; 
    pthread_mutex_unlock (&mutex); 
    pthread_cond_broadcast (&cond); // NOTE: broadcast, not signal! 
    return NULL; 
} 
else 
    pthread_cond_wait(&cond, &mutex); 
pthread_mutex_unlock (&mutex); 

Обратите внимание, что pthread_cond_broadcast необходимо, как вы хотите, чтобы проснуться все темы.

+0

Вышеуказанные изменения дают мне те же результаты, без изменений. –

+0

Да, действительно. Обратите внимание на последнее изменение. Он фиксирует условие гонки и использует широковещательную передачу вместо сигнала, который действительно необходим в этом случае использования. Мне иногда удалось воспроизвести проблему, и теперь она всегда работает для меня. – juhist

+0

Спасибо, я могу видеть отпечатки только от 'function1' &' function2', а не от остальных. Вот точный код, который я использую http://paste.ubuntu.com/10683407/. Я буду рассматривать «pthread_cond_broadcast» параллельно. –

Смежные вопросы