测试队列中等待 condition_variables 的多个线程

Testing multiple threads waiting on condition_variables in a queue

我正在测试如何将等待 condition_variables 的对象推送到队列中。我想按照我的意愿执行线程,因为它们稍后会在关键部分。线程没有打印任何内容,可能是哪里出了问题?

mutex print_mu;

void print(function<void()> func)
{
    lock_guard<mutex> lock(print_mu);
    func();
}

unsigned int generate_id()
{
    static unsigned int id = 1;
    return id++;
}

class foo
{
    unsigned int id_;
    mutex mu_;
    condition_variable cv_;
    bool signal_;
    bool& kill_;
public:
    foo(bool kill) 
        :kill_(kill) 
        , signal_(false)
        , id_(generate_id())
    {
        run();
    }

    void set()
    {
        signal_ = true;
    }

    void run()
    {
        async(launch::async, [=]()
        {
            unique_lock<mutex> lock(mu_);
            cv_.wait(lock, [&]() { return signal_ || kill_ ; });

            if (kill_)
            {
                print([=](){ cout << " Thread " << id_ << " killed!" << endl; });
                return;
            }

            print([=](){ cout << " Hello from thread " << id_ << endl; });
        });
    }
};

int main()
{
    queue<shared_ptr<foo>> foos;
    bool kill = false;

    for (int i = 1; i <= 10; i++)
    {
        shared_ptr<foo> p = make_shared<foo>(kill);
        foos.push(p);
    }
    this_thread::sleep_for(chrono::seconds(2));

    auto p1 = foos.front();
    p1->set();
    foos.pop();

    auto p2 = foos.front();
    p2->set();
    foos.pop();

    this_thread::sleep_for(chrono::seconds(2));

    kill = true; // terminate all waiting threads unconditionally

    this_thread::sleep_for(chrono::seconds(2));

    print([=](){ cout << " Main thread exits" << endl; });

    return 0;
}

当一个线程调用 std::condition_variable::wait 时,它会阻塞,直到另一个线程在同一个 condition_variable 上调用 notify_onenotify_all。因为你永远不会在任何 condition_variables 上调用 notify_*,它们将永远阻塞。

您的 foo::run 方法也将永远阻塞,因为 std::future 的析构函数将阻塞等待 std::async 调用的结果,如果它是最后一个 std::future 引用那个结果。因此你的代码死锁:你的主线程被阻塞等待你的异步未来完成,你的异步未来被阻塞等待你的主线程发出信号 cv_.

(另外 foo::kill_ 是一个悬空引用。好吧,如果 run 无论如何返回它就会变成一个悬空引用。)