【发布时间】:2020-06-13 13:00:57
【问题描述】:
多生产者单消费者场景,除了消费发生一次,之后队列“关闭”并且不允许更多工作。我有一个 MPSC 队列,所以我尝试添加一个无锁算法来“关闭”队列。我相信它是正确的,它通过了我的测试。问题是当我尝试优化内存顺序时它停止工作(我认为工作丢失了,例如在队列关闭后排队)。即使在具有“某种”强内存模型的 x64 上,即使只有一个生产者。
我对内存顺序进行微调的尝试被注释掉了:
// thread-safe for multi producers single consumer use
// linked-list based, and so it's growable
MPSC_queue work_queue;
std::atomic<bool> closed{ false };
std::atomic<int32_t> producers_num{ 0 };
bool produce(Work&& work)
{
bool res = false;
++producers_num;
// producers_num.fetch_add(1, std::memory_order_release);
if (!closed)
// if (!closed.load(std::memory_order_acquire))
{
work_queue.push(std::move(work));
res = true;
}
--producers_num;
// producers_num.fetch_sub(1, std::memory_order_release);
return res;
}
void consume()
{
closed = true;
// closed.store(true, std::memory_order_release);
while (producers_num != 0)
// while (producers_num.load(std::memory_order_acquire) != 0)
std::this_thread::yield();
Work work;
while (work_queue.pop(work))
process(work);
}
我还尝试了std::memory_order_acq_rel 对producers_num 的读-修改-写操作,也不起作用。
一个额外的问题:
该算法与 MPSC 队列一起使用,它已经在内部进行了一些同步。将它们结合起来以获得更好的性能会很好。你知道“可关闭”MPSC 队列的任何此类算法吗?
【问题讨论】:
-
work_queue.push到底是做什么的?那是线程安全的吗?您似乎遗漏了变量声明等关键细节。 -
这是 MPSC 队列 - 无锁多生产者单消费者
-
@PeterCordes:添加了缺失的细节
-
由于您只想使用一次队列,它不需要环绕并且可能会简单得多。就像一个原子生产者位置计数器,作者递增以声明一个位置,如果他们得到一个位置 > 大小,那么队列就满了。
-
@PeterCordes:不确定我是否关注。队列永远不会满,因为它是基于链表的。这可能是一个重要的细节,添加到问题中
标签: c++ multithreading lock-free