【问题标题】:What will be the critical section code for a shared queue accessed by two threads?两个线程访问的共享队列的临界区代码是什么?
【发布时间】:2011-07-27 04:27:08
【问题描述】:

假设我们有一个共享队列(使用数组实现),两个线程可以访问该队列,一个用于从中读取数据,另一个用于向其写入数据。现在,我有一个同步问题。我正在使用 Win32 API(EnterCriticalSection 等)来实现这一点。

但我的好奇心是队列的入队和出队操作中的临界区代码是什么?

仅仅因为,两个线程正在使用共享资源?为什么我看不到任何问题是这样的:前后端都被维护了,所以当ReaderThread读取时,它可以从前端读取,而当WriterThread写入时,它可以很容易地写入后端。

可能会出现哪些潜在问题?

【问题讨论】:

  • 如果您只有 1 个条目因此 tail = head 怎么办?
  • 应该没问题。如果您锁定了该部分,则读取器将获取数据而无需写入器在读取器顶部添加数据,并且读取器不会删除数据,从而导致下一个空槽偏移量对于写入器不正确。实际上,只要作者从不改变前面,你不需要一个关键部分,除了读者正在删除它已经阅读的部分,如果作者同时试图写,读者改变了下一个从作者下方偏移,因为它没有同步。

标签: c++ multithreading critical-section


【解决方案1】:

对于单个生产者/消费者循环队列实现,实际上不需要锁。只需设置一个条件,即如果队列已满,则生产者无法写入队列,如果队列为空,则消费者无法从队列中读取。此外,生产者将始终写入指向队列中第一个可用空槽的tail 指针,而消费者将从代表队列中第一个未读槽的head 指针读取。

您的代码可能类似于以下代码示例(注意:我假设在初始化队列中 tail == head,并且两个指针都声明为 volatile,因此优化编译器不会重新排序给定线程内的操作。在 x86 上,由于架构的强内存一致性模型,不需要内存屏障,但在其他需要内存屏障的内存一致性模型较弱的架构上,这会有所改变):

queue_type::pointer queue_type::next_slot(queue_type::pointer ptr);

bool queue_type::enqueue(const my_type& obj)
{
    if (next_slot(tail) == head)
        return false;

    *tail = obj;
    tail = next_slot(tail);

    return true;
}

bool queue_type::dequeue(my_type& obj)
{
    if (head == tail)
        return false;

    obj = *head;
    head = next_slot(head);

    return true;
}

函数next_slot 简单地递增headtail 指针,以便它返回指向数组中下一个槽的指针,并考虑任何数组环绕功能。

最后,我们保证单生产者/消费者模型中的同步,因为我们不会增加 tail 指针,直到它将数据写入它指向的插槽,并且我们不会增加 head 指针直到我们已经从它指向的插槽中读取了数据。因此,对dequeue 的调用将不会返回有效,直到至少对enequeue 进行了一次调用,并且tail 指针永远不会覆盖head 指针,因为enqueue 中的检查。此外,只有一个线程递增 tail 指针,而一个线程递增 head 指针,因此共享读取或写入同一指针不会产生同步问题,需要锁定或某种类型的原子操作。

【讨论】:

  • 太糟糕了,我只能给+1!很好的答案。
  • 这很酷,如果队列“忙”时我不想等待。所以我必须写while(queue.enqueue(obj) != 0); 以确保obj 被推回队列,这不是那么酷。
  • @sad_man:如果队列已满/空,您可以在入队/出队时阻止生产者/消费者,并使用事件唤醒相应线程。
  • @ChrisWue:我认为使用事件给问题增加了几乎相同(甚至更多)的复杂性。使用临界区也是更高效的解决方案。
  • 如果您在多 CPU 环境中运行,自旋锁将是迄今为止最快的解决方案。自旋锁只不过是对原子变量的忙等待形式。该解决方案避免了必须由内核仲裁的较慢的锁,并且只有当队列为空或已满时才需要任何忙等待。例如,如果将此队列用作快速数据管道中的消息队列,您需要最快的入队和出队操作来减少延迟,那么您几乎不会遇到长时间的忙等待……您绝对不会想要触摸内核。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-26
  • 1970-01-01
  • 1970-01-01
  • 2012-07-27
  • 2020-08-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多