Нужен ли мне Mutex при использовании кругового буфера и шаблона проектирования "производитель / потребитель"
У меня есть два потока, которые общаются через кольцевой буфер.
/* Initialize not_full semaphore to a count of BUFFER_SIZE */
sem_init(¬_full_semaphore, 0, BUFFER_SIZE);
/* Initialize not_empty semaphore to a count of 0 */
sem_init(¬_empty_semaphore, 0, 0);
void producer_thread (void) {
int item
int head = 0;
while(true) {
item = produce_item();
sem_wait(¬_full_semaphore);
mutex_lock(&circular_buffer_mutex);
/* Insert item into the buffer */
circular_buffer[head] = item;
/* Increment head offset and wrap if necessary */
head = (head == BUFFER_SIZE - 1) ? 0 : head + 1;
mutex_unlock(&circular_buffer_mutex);
sem_post(¬_empty_semaphore);
}
}
void consumer_thread (void){
int item;
int tail = 0;
while(true) {
sem_wait(¬_empty_semaphore);
mutex_lock(&circular_buffer_mutex);
/* Remove item from the buffer */
item = circular_buffer[tail];
/* Increment tail offset and wrap if necessary */
tail = (tail == BUFFER_SIZE - 1) ? 0 : tail + 1;
mutex_unlock(&circular_buffer_mutex);
sem_post(¬_full_semaphore);
consume_item(item);
}
Мой вопрос: действительно ли мне нужен мьютекс? Мне кажется, что нет никаких шансов, что производитель и потребитель когда-либо будут иметь доступ к одной и той же памяти одновременно. Потребитель не будет читать, пока продюсер не закончит запись и не сообщит об этом через семафор not_empty. Кроме того, семафору not_full будет запрещено продвигать продюсера и писать снова. Так что мне не кажется, что мне нужен мьютекс, но все примеры, которые я нашел, используют его.
1 ответ
Мой вопрос: действительно ли мне нужен мьютекс?
Да, вы делаете.
Без мьютекса, так как вы инициализируете not_full_semaphore
к значению, которое потенциально больше единицы, в этом коде:
while(true) {
item = produce_item();
sem_wait(¬_full_semaphore);
// can reach here while the consumer thread is
// accessing the circular buffer
// but this mutex prevents both threads from
// accessing the circular buffer simultaneously
mutex_lock(&circular_buffer_mutex);
ваш поток производителя не будет ждать завершения потока потребителя, прежде чем производить следующий элемент.
Кроме того, семафору not_full будет запрещено продвигать продюсера и писать снова.
Это не правильно. Поток производителя не должен ждать потока потребителя, если not_full_semaphore
инициализируется значением больше единицы.