【问题标题】:Can multiple threads wait on the same condition variable?多个线程可以等待同一个条件变量吗?
【发布时间】:2019-08-01 00:23:08
【问题描述】:

我正在尝试了解如何更好地使用条件变量,并且我有以下代码。

行为。

代码的预期行为是:

  1. 每个线程打印“线程n等待”
  2. 程序一直等到用户按下回车键
  3. 当用户按下回车键时,notify_one 会为每个线程调用一次
  4. 所有线程都打印“thread n ready.”,然后退出

代码的观察到的行为是:

  1. 每个线程打印“线程n等待”(预期)
  2. 程序一直等到用户按下回车键(预期)
  3. 当用户按下回车键时,每个线程都会调用一次 notify_one (预期)
  4. 其中一个线程打印“线程 n 就绪”,但随后代码挂起。 (???)

问题。

为什么代码会挂起?以及如何让多个线程等待同一个条件变量?

代码

#include <condition_variable>
#include <iostream>
#include <string>
#include <vector>
#include <thread>

int main() {

    using namespace std::literals::string_literals; 
    auto m = std::mutex(); 

    auto lock = std::unique_lock(m);

    auto cv = std::condition_variable(); 

    auto wait_then_print =[&](int id) {
        return [&, id]() {
            auto id_str = std::to_string(id); 
            std::cout << ("thread " + id_str + " waiting.\n"); 
            
            cv.wait(lock); 
            // If I add this line in, the code gives me a system error:
            // lock.unlock();

            std::cout << ("thread " + id_str + " ready.\n"); 
        };
    };

    auto threads = std::vector<std::thread>(16); 

    int counter = 0; 
    for(auto& t : threads)
        t = std::thread(wait_then_print(counter++));

    std::cout << "Press enter to continue.\n"; 

    std::getchar(); 

    for(int i = 0; i < counter; i++) {
        cv.notify_one();
        std::cout << "Notified one.\n";
    }

    for(auto& t : threads)
        t.join(); 
}

输出

thread 1 waiting.
thread 0 waiting.
thread 2 waiting.
thread 3 waiting.
thread 4 waiting.
thread 5 waiting.
thread 6 waiting.
thread 7 waiting.
thread 8 waiting.
thread 9 waiting.
thread 11 waiting.
thread 10 waiting.
thread 12 waiting.
thread 13 waiting.
thread 14 waiting.
thread 15 waiting.
Press enter to continue.

Notified one.
Notified one.
thread 1 ready.
Notified one.
Notified one.
Notified one.
Notified one.
Notified one.
Notified one.
Notified one.
Notified one.
Notified one.
Notified one.
Notified one.
Notified one.
Notified one.
Notified one.

【问题讨论】:

  • 当您不持有锁时,您正在调用cv.wait(lock) - 未定义的行为,但通常会先获取锁。由于您永远不会释放锁,因此只有第一个线程可以打印其消息,其余所有线程都在等待永远不会释放的锁......

标签: c++ multithreading condition-variable


【解决方案1】:

这是未定义的行为。

为了等待条件变量,条件变量必须由最初锁定互斥锁的完全相同的线程等待。您不能将互斥锁锁定在一个执行线程中,然后在另一个线程中等待条件变量。

auto lock = std::unique_lock(m);

这个锁是在主执行线程中获得的。之后,主执行线程创建所有这些多个执行线程。这些执行线程中的每一个都执行以下操作:

       cv.wait(lock)

这里调用wait()的执行线程没有获取互斥锁,因此这是未定义的行为。

更仔细地观察你在这里尝试做的事情表明,如果你只是移动,你可能会得到你想要的结果

auto lock = std::unique_lock(m);

在每个新执行线程执行的 lambda 内部。

由于各种竞争条件,您还需要简单地使用notify_all() 而不是多次调用notify_one()。请记住,wait() 自动解锁互斥锁并等待条件变量,而wait() 只有在线程收到条件变量通知后成功重新锁定互斥锁后才会返回。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-04
    • 2020-05-20
    • 2011-07-21
    • 1970-01-01
    • 1970-01-01
    • 2015-08-23
    相关资源
    最近更新 更多