【问题标题】:Two-Lock Concurrent Queue Algorithm Issue双锁并发队列算法问题
【发布时间】:2016-05-21 23:26:54
【问题描述】:

所以我正在阅读 Maged M. Michael 和 Michael L. Scott 的文章 Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms,但有一个小问题我没有明白:

假设我们有两个并发线程,它们在队列初始化后立即被触发。其中一个线程调用enqueue,另一个调用dequeue。是什么阻止他们同时访问虚拟节点的next 字段? dequeue 线程不能读取next 字段而enqueue 线程写入它吗?他们都使用不同的锁......所以我不明白它们之间的同步......

谢谢。

【问题讨论】:

  • 你指的是哪个虚拟节点?
  • 在initialize()中创建的那个
  • 我猜你指的是在初始化中创建的第一个节点?
  • 是的,我指的是那个

标签: c++ multithreading concurrency synchronization locking


【解决方案1】:

enqueue() 只操作尾部,dequeue() 只操作头部,所以它们不需要使用相同的锁。当 head 和 tail 指向同一个节点时,有一种特殊情况,即在初始化时创建的“虚拟”节点。你是正确的, enqueue() 可能正在写入该节点的 next 指针,而 dequeue() 正在尝试读取它。

并发读写没有问题。请注意,enqueue() 创建了一个新节点,并完全初始化该对象,然后通过将其写入 tail->next 使其可见。因此,没有其他代码可以看到这个处于中途初始化状态的新节点。此外,对指针的读/写是原子的,因此 dequeue() 不可能获得指针的一半。

所以在你的 enqueue() 和 dequeue() 都被立即调用的场景中,有两种可能性:

  • enqueue() 在 dequeue() 从 head->next 读取之前写入 tail->next。在这种情况下,dequeue() 将看到已入队的节点并将其返回。
  • dequeue() 在 enqueue() 写入 tail->next 之前从 head->next 读取。在这种情况下,dequeue() 认为队列为空并返回 false。

【讨论】:

  • 谢谢 - 我不知道指针的读/写是原子的。
  • 所以我猜这个算法的正确性取决于实现。因为正如我现在所读到的,例如,在 C++ 中并不能真正保证指针操作是原子的。
  • 对,似乎在 C++ 中你想使用原子指针:en.cppreference.com/w/cpp/atomic/atomic。它确实取决于您使用的语言的内存模型。
猜你喜欢
  • 2015-08-26
  • 1970-01-01
  • 2019-06-05
  • 1970-01-01
  • 2017-03-28
  • 1970-01-01
  • 1970-01-01
  • 2011-10-14
  • 2010-12-06
相关资源
最近更新 更多