【问题标题】:Do I need a Mutex when using a circular buffer and the Producer / Consumer design pattern使用循环缓冲区和生产者/消费者设计模式时是否需要互斥锁
【发布时间】:2018-09-26 16:39:41
【问题描述】:

我有两个线程通过循环缓冲区进行通信。

/* 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 信号量将阻止生产者回绕并再次写入。所以在我看来我不需要互斥锁,但我发现的所有示例都使用了它。

【问题讨论】:

  • 在只有一个生产者和一个消费者的特定情况下,并且给定一个头索引只有生产者访问和尾索引只有消费者访问的队列结构,你可以不用互斥锁。

标签: c multithreading mutex


【解决方案1】:

我的问题是我真的需要互斥锁吗?

是的,你知道。

没有互斥锁,因为您将 not_full_semaphore 初始化为一个可能大于 1 的值,在此代码中:

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 被初始化为大于 1 的值,则生产者线程不必等待消费者线程。

【讨论】:

  • 假设缓冲区中有 8 个空格。然后 not_full 被初始化为 8 而 not_empty 被初始化为 0。缓冲区中的每个空间都明确地为一个线程或另一个线程留出了空间(有一个空缓冲区,全部交给生产者)。每个线程只有在完成后才将一个空间交给另一个线程。如果两个线程同时运行有问题,你还没有解释是什么问题。
  • 但是生产者线程应该能够产生与循环缓冲区中的空间一样多的项目。一旦它满了,生产者线程将被阻止再生产,直到消费者线程消耗了一些。我的观点是,只要他们不访问循环缓冲区中的相同位置,让他们都访问它有什么害处?
  • @ACRL 你的结论是正确的,信号量可以自己管理队列计数。互斥锁用于防止在队列上执行操作时损坏,例如:'/* 增加尾部偏移量并在必要时换行 */' 考虑一下 - 有多个生产者和消费者线程,并且队列半满,可能会有许多线程试图并行操作队列索引,导致 TOCTTOU....“事件”
猜你喜欢
  • 2014-03-26
  • 2019-06-13
  • 1970-01-01
  • 2017-04-07
  • 2019-05-18
  • 1970-01-01
  • 1970-01-01
  • 2016-06-06
  • 2020-01-21
相关资源
最近更新 更多