2016-10-26 27 views
1

Мой исходный код ниже работает именно так, как предполагалось. Проблема в том, что мне удалось заставить ее работать только потому, что я использовал команды print f, чтобы узнать, где код «застревает». Я не понимаю, почему во внутренних циклах мьютексы должны быть разблокированы, а не заблокированы функцией, использующей его. Простите, если это не очень понятно, но у меня проблемы с пониманием этого.Должен ли этот мьютекс «блокировать», если вы пытаетесь получить доступ к глобальной переменной?

Для здравомыслия, я поставил снимок кода под вопросом сам по себе и полный исходный код под ним.

  // if buffer is full, release mutex lock and check again 
     if (shared_count == NITEMS) 
     { 
      // Signal consumer thread and sleep 
      pthread_cond_signal(&bufferNotEmpty); 
      pthread_cond_wait(&bufferNotFull,&mutex); 
      pthread_mutex_unlock(&mutex); 
      break; 
     } 

Вот полный исходный код:

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

#define NITEMS 10    // number of items in shared buffer 

// shared variables 
char shared_buffer[NITEMS];  // echo buffer 
int shared_count;    // item count 

pthread_mutex_t mutex;   // pthread mutex 
pthread_cond_t bufferNotEmpty; // pthread condition variable for consumer thread 
pthread_cond_t bufferNotFull; // pthread condition variable for producer thread 

unsigned int prod_index = 0; // producer index into shared buffer 
unsigned int cons_index = 0; // consumer index into shared buffer 

// function prototypes 
void * producer(void *arg); 
void * consumer(void *arg); 

int main() 
{ 
    pthread_t prod_tid, cons_tid1, cons_tid2; 

    // initialize pthread variables 
    pthread_mutex_init(&mutex, NULL); 
    pthread_cond_init(&bufferNotEmpty, NULL); 
    pthread_cond_init(&bufferNotFull, NULL); 

    // start producer thread 
    pthread_create(&prod_tid, NULL, producer, NULL); 

    // start consumer threads 
    pthread_create(&cons_tid1, NULL, consumer, NULL); 
    pthread_create(&cons_tid2, NULL, consumer, NULL); 

    // wait for threads to finish 
    pthread_join(prod_tid, NULL); 
    pthread_join(cons_tid1, NULL); 
    pthread_join(cons_tid2, NULL); 

    // clean up 
    pthread_mutex_destroy(&mutex); 
    pthread_cond_destroy(&bufferNotEmpty); 
    pthread_cond_destroy(&bufferNotFull); 

    return 0; 
} 

// producer thread executes this function 
void * producer(void *arg) 
{ 
    char key; 

    while (1) 
    { 
     // read input key 
     scanf("%c", &key); 

     while (1) 
     { 
      // acquire mutex lock 
      pthread_mutex_lock(&mutex); 

      // if buffer is full, release mutex lock and check again 
      if (shared_count == NITEMS) 
      { 
       // Signal consumer thread and sleep 
       pthread_cond_signal(&bufferNotEmpty); 
       pthread_cond_wait(&bufferNotFull,&mutex); 
       pthread_mutex_unlock(&mutex); 
       break; 
      } 

      else 
       break; 
     } 

     // store key in shared buffer 
     shared_buffer[prod_index] = key; 

     // update shared count variable 
     shared_count++; 


     // update producer index 
     if (prod_index == NITEMS - 1) 
      prod_index = 0; 
     else 
      prod_index++; 

     // release mutex lock and signal consumer thread 
     pthread_mutex_unlock(&mutex); 
     pthread_cond_signal(&bufferNotEmpty); 
    } 

    return NULL; 
} 

// consumer thread executes this function 
void * consumer(void *arg) 
{ 
    char key; 

    int id = (int)pthread_self(); 

    while (1) 
    { 
     while (1) 
     { 
      // acquire mutex lock 
      pthread_mutex_lock(&mutex); 

      // if buffer is empty, wake producer thread and sleep 
      if (shared_count == 0) 
      { 
       pthread_cond_signal(&bufferNotFull); 
       pthread_cond_wait(&bufferNotEmpty,&mutex); 
       pthread_mutex_unlock(&mutex); 
      } 

      else 
       break; 
     } 

     // read key from shared buffer 
     key = shared_buffer[cons_index]; 

     // echo key 
     printf("consumer %d %c\n", id, key); 

     // update shared count variable 
     shared_count--; 

     // update consumer index 
     if (cons_index == NITEMS - 1) 
      cons_index = 0; 
     else 
      cons_index++; 

     // release mutex lock and signal producer thread 
     pthread_mutex_unlock(&mutex); 
     pthread_cond_signal(&bufferNotFull); 
    } 

    return NULL; 
} 

ответ

5

У вас есть шаблон ждать неправильно. Это:

// acquire mutex lock 
    pthread_mutex_lock(&mutex); 

    // while buffer is empty, wait 
    while (shared_count == 0) 
    { 
     pthread_cond_wait(&bufferNotEmpty,&mutex); 
    } 

    // read key from shared buffer 
    key = shared_buffer[cons_index]; 

    // echo key 
    printf("consumer %d %c\n", id, key); 

    // update shared count variable 
    shared_count--; 

    // update consumer index 
    if (cons_index == NITEMS - 1) 
     cons_index = 0; 
    else 
     cons_index++; 

    // release mutex lock and signal producer thread 
    pthread_mutex_unlock(&mutex); 
    pthread_cond_signal(&bufferNotFull); 

Исправить другую сторону таким же образом. Вам нужен цикл, который ждет, пока условие не будет удовлетворено, и вы хотите удержать (возможно, повторно приобретенный) мьютекс, когда вы возитесь с общим состоянием.

Уведомление Я удалил первый звонок pthread_cond_signal. Независимо от того, сделалshared_count равным нулю уже прозрел бы другой поток. Мы ничего не изменили, так что нам пока еще ничего не нужно рассказывать.

Нет смысла уведомлять другую тему, если вы не сделали ничего, о чем необходимо сообщить. Вы вызываете pthread_cond_signal, когда вам нужно сообщить другому потоку, что вы изменили какое-то общее состояние, которое оно может ждать.

+0

Я в замешательстве, способ, которым мой код реализован, теперь работает нормально. Вы говорите, что это не должно работать или что способ, которым вы предоставили, - это лучший способ достичь цели? – Remixt

+0

@Remixt Я говорю, что вы получили его для работы сложным способом, который отражает недостаточное понимание того, как правильно использовать функции. Он также частично работает удачей, потому что он неправильно обрабатывает ложные пробуждения и может разблокировать мьютекс дважды подряд. –

+0

Спасибо за разъяснение. Я ценю это. – Remixt

2

После успешного возвращения, мьютекс должен быть заблокирован и должен быть принадлежит вызывающему потоку

https://linux.die.net/man/3/pthread_cond_wait

pthread_cond_wait() заблокирует семафор, поэтому вызов

pthread_cond_wait(&bufferNotEmpty,&mutex); 
// mutex is already locked 
pthread_mutex_lock(&mutex); 
// deadlock 

приведет к тупику

+1

Спасибо за разъяснение! – Remixt

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

  • Нет связанных вопросов^_^