2010-11-05 4 views
2

Я пытаюсь работать с потоками производителя/потребителя в ограниченном буфере. Длина буфера равна 5. У меня есть 1 мьютекс и 2 семафора, пустой, который начинается с размера буфера, и полный, который начинается с 0.C - проблема блокировки производителя/потребителя

Когда я запускаю свой код без сна() в конце она постоянно производит до тех пор, пока буфер не полностью полностью, то истребляют, пока он не пуст, поэтому результат выглядит следующим образом:

Placed 1 in the buffer at position 0. 
Placed 2 in the buffer at position 1. 
Placed 3 in the buffer at position 2. 
Placed 4 in the buffer at position 3. 
Placed 5 in the buffer at position 4. 
The buffer now contains 0 at position 0. 
The buffer now contains 0 at position 1. 
The buffer now contains 0 at position 2. 
The buffer now contains 0 at position 3. 
The buffer now contains 0 at position 4. 

Однако, когда я бегу со сном() в конце, он печатает:

Placed 1 in the buffer at position 0. 
The buffer now contains 0 at position 0. 

Затем он заперт, но я не уверен, почему он ведет себя y это независимо от того, есть или нет сон. Какие-либо предложения? Мой основной метод, по сути, просто делает некоторые объявления, а затем создает 1 поток для производства и 1 для потребления, эти методы ниже.

void *producer() 
{ 
     int k = 0; //producer index 
     while (1) 
     { 
       sem_wait(&empty); 
       pthread_mutex_lock(&mutex); 
       buffer[k] = k+1; 
       sem_post(&full); 
       pthread_mutex_unlock(&mutex); 
       printf("Placed %d in the buffer at position %d.\n", buffer[k], k); 
       k = (k + 1) % BUFFER_SIZE; 
       sleep(rand() * 10); 
     } 
} 

void *consumer() 
{ 
     int j = 0; //consumer index 
     while(1) 
     { 
       sem_wait(&full); 
       pthread_mutex_lock(&mutex); 
       buffer[j] = 0; 
       sem_post(&empty); 
       pthread_mutex_unlock(&mutex); 
       printf("The buffer now contains %d at position %d.\n", buffer[j], j); 
       j = (j + 1) % BUFFER_SIZE; 
       sleep(rand() * 10); 

     } 
} 
+0

Предлагаю вам выбросить код и переписать задачу в псевдокоде. Или вы можете переписать его на C снова, что обычно помогает мне найти такие жесткие ошибки. –

+0

Одна (не связанная) проблема. Я вижу, потребительский индекс 'j' должен делиться между потребителями. Это не помогает, если оно локально для каждого потока. Сделайте 'j' глобальным. –

+0

Спасибо, я на самом деле планировал это сделать, когда я реализую несколько потоков, но пока у меня только 1 производитель и 1 потребитель каждый. – john

ответ

3

Параметр на sleep() - количество секунд до сна. rand() возвращает целое число от 0 до RAND_MAX (обычно 32767 или 2 -1), и когда вы умножаете это на 10, вы спите для абсурдно большого количества времени. Вы не зашли в тупик, просто спали очень долго.

+0

Хм, почему-то я думал, что rand() находится между 0 и 1. Спасибо, я постараюсь его настроить. – john

+0

Это сработало, спасибо. У вас есть идеи, почему, когда я не включаю сон, он всегда производит и потребляет в блоках, а не в других? – john

+0

@john Если вы ничего не навязываете, вы обычно получаете наиболее эффективный результат. –

2

Я не знаю, если это является причиной вашего тупика, но вы должны быть осторожны с sem_t функций, которые они подлежат прерывания, в частности, из-за ввод-вывод и тому подобных.

Никогда не игнорируйте возврат из системных функций. Здесь вам нужно будет проверить возврат, а затем errno за EINTR.

Тогда, я не знаю, если вы вынуждены использовать sem_t, но я думаю, что более естественным здесь будет использование pthread_cond_t. У вас есть мьютекс, так что это будет легче. pthread_cond_t как функции pthread_mutex_t никогда не будут прерваны.

0

Предполагаю, что оба потока имеют такой же приоритет? И это на машине с несколькими ядрами или только с одним? Просто сигнализация семафора не будет вытеснять ваш текущий поток, поэтому следует ожидать, что текущий поток будет продолжаться, пока его срез не истечет.

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

+0

Машина, на которой я работаю, является двухъядерным. Если потребительский поток работает в одно и то же время, постоянно проверяя условие, что он может начать потреблять, а поток производителя сигнализирует семафор после 1 производства, не должен ли потребитель запускать работу после того, как производитель запускает один раз? – john

+0

Он должен. Кстати, для чего это мьютекс? Поскольку вы сигнализируете семафор после того, как закончите писать (как и следовало ожидать), вы гарантированно никогда не будете писать на тот же адрес, который читает потребительский поток. – EboMike

+0

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

1

Do you have any idea why when I don't include sleep it always produces and consumes in blocks instead of every other?

То, вероятно, потому, что ~ 30 мс временной срез каждого потока задается более чем достаточно, чтобы производитель производить все до переключения контекста был шанс произойти.

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