【发布时间】:2013-04-26 16:51:11
【问题描述】:
建议包含在 C++14(又名 C++1y)中的是一些新的线程同步原语:锁存器和屏障。建议是
这听起来是个好主意,示例使它看起来对程序员非常友好。不幸的是,我认为示例代码调用了未定义的行为。该提案提到latch::~latch():
破坏闩锁。如果闩锁在其他线程处于
wait()或正在调用count_down()时被销毁,则行为未定义。
请注意,它说的是“在wait()”中,而不是“在wait() 中被阻止”,正如count_down() 的描述所使用的那样。
那么提供以下示例:
第二个用例的示例如下所示。我们需要加载数据,然后使用多个线程对其进行处理。加载数据受 I/O 限制,而启动线程和创建数据结构受 CPU 限制。通过并行运行这些,可以增加吞吐量。
void DoWork() { latch start_latch(1); vector<thread*> workers; for (int i = 0; i < NTHREADS; ++i) { workers.push_back(new thread([&] { // Initialize data structures. This is CPU bound. ... start_latch.wait(); // perform work ... })); } // Load input data. This is I/O bound. ... // Threads can now start processing start_latch.count_down(); }
从wait() 唤醒和返回的线程与离开作用域时锁存器的破坏之间是否存在竞争条件?除此之外,所有thread 对象都被泄露。如果调度程序在count_down 返回并且start_latch 对象离开范围之前没有运行所有工作线程,那么我认为会导致未定义的行为。大概解决方法是在count_down 之后但在返回之前迭代向量和join() 和delete 所有工作线程。
- 示例代码有问题吗?
- 您是否同意提案应显示完整正确的示例,即使任务非常简单,以便审阅者了解使用体验?
注意:似乎有一个或多个工作线程尚未开始等待,因此将在已损坏的闩锁上调用 wait()。
更新:现在有一个新版本的提案,但代表性示例没有改变。
【问题讨论】:
-
@stefan:我不认为“释放阻塞线程”包括“至少等待那些线程运行直到从
wait()返回” -
此外,其中一个线程可能还没有*到达`
start_latch.wait()调用。 -
我同意你的看法。好像例子坏了……
标签: c++ race-condition language-lawyer c++14