Нужен ли мне Mutex при использовании кругового буфера и шаблона проектирования "производитель / потребитель"

У меня есть два потока, которые общаются через кольцевой буфер.

/* Initialize not_full semaphore to a count of BUFFER_SIZE */
sem_init(&not_full_semaphore, 0, BUFFER_SIZE);
/* Initialize not_empty semaphore to a count of 0 */
sem_init(&not_empty_semaphore, 0, 0);

void producer_thread (void) {
    int item
    int head = 0;

    while(true) {
        item = produce_item();

        sem_wait(&not_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(&not_empty_semaphore);
    }
}

void consumer_thread (void){
    int item;
    int tail = 0;

    while(true) {
        sem_wait(&not_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(&not_full_semaphore);
        consume_item(item);
    }

Мой вопрос: действительно ли мне нужен мьютекс? Мне кажется, что нет никаких шансов, что производитель и потребитель когда-либо будут иметь доступ к одной и той же памяти одновременно. Потребитель не будет читать, пока продюсер не закончит запись и не сообщит об этом через семафор not_empty. Кроме того, семафору not_full будет запрещено продвигать продюсера и писать снова. Так что мне не кажется, что мне нужен мьютекс, но все примеры, которые я нашел, используют его.

1 ответ

Мой вопрос: действительно ли мне нужен мьютекс?

Да, вы делаете.

Без мьютекса, так как вы инициализируете not_full_semaphore к значению, которое потенциально больше единицы, в этом коде:

while(true) {
    item = produce_item();

    sem_wait(&not_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 инициализируется значением больше единицы.

Другие вопросы по тегам