延迟的线程启动-通知所有未唤醒所有线程 [英] Delayed Thread Start - Notify All Not Waking All Threads

查看:117
本文介绍了延迟的线程启动-通知所有未唤醒所有线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尝试:

要在多个线程上延迟启动.

To do a delayed start on multiple threads.

问题:

我创建了下面的示例来证明这一想法,并尝试在x上创建一个竞争条件,以证明所有线程将同时运行.

I've created the example below to prove out the idea and attempted to create a race codition on x to prove out that all the threads would run concurrently.

似乎事情是序列化而不是并行运行-这是所需的行为,但是也许每个线程运行的时间都太短,并且在另一个线程获得服务之前完成了

It seems like things are serialize instead of running in parallel-the desired behavior, but maybe each thread runs for too short a period and finishes before the other onse get serviced

有时,某个线程将卡在cv.wait上---我已经在GDB中查看了它,并且可以看到其中一个线程正坐在第0帧的等待中---这意味着notify_all并没有唤醒所有线程---(这是零星的行为,每运行几次二进制程序都会发生一次

Sometimes a thread will get stuck on the cv.wait --- I've viewed this in GDB and can see one of the threads just sitting on the wait in frame 0 --- meaning the notify_all did not wak ALL the threads --- (this is sporadic behavior and happens every few attempts at running the binary)

询问:

  1. 使用条件变量是否是一种有效的方法,用于以一组期望的行为来延迟启动一组线程,这些线程将全部并行运行?

  1. Is using the condition variable a valid method for performing a delayed startup of a group of threads with the desired behavior that they will all run in parallel?

为什么notify_all()不唤醒所有线程?

Why is the notify_all() not waking ALL the threads?

代码:

// main.cpp
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <atomic>
#include <iostream>
#include <unistd.h>

int main()
{
    std::condition_variable cv;
    std::mutex cv_m;
    int x = 0;
    std::thread t1 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t1 x:" << x++ << std::endl;});
    std::thread t2 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t2 x:" << x++ << std::endl;});
    std::thread t3 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t3 x:" << x++ << std::endl;});
    std::thread t4 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t4 x:" << x++ << std::endl;});
    std::thread t5 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t5 x:" << x++ << std::endl;});
    std::cout << "STARTING" << std::endl;
    cv.notify_all();
    t1.join();
    t2.join();
    t3.join();
    t4.join();
    t5.join();
    std::cout << "DONE" << std::endl;
    return 0;
}

编译:

g++ -std=c++14 main.cpp -lpthread

运行:

./a.out

推荐答案

条件变量是无状态的.如果没有服务员,通知会丢失;可以发送spurios通知.您需要等待共享状态的更改,而不是条件变量发出的信号.

Condition variables are stateless. Notifications get lost if there are no waiters; spurios notifications can be delivered. You need to wait for a change of a shared state, rather than a signal from a condition variable.

std :: condition_variable :

当通知条件变量,超时到期或发生虚假唤醒时,将唤醒线程,并自动重新获取互斥量.然后,线程应检查条件,如果唤醒是虚假的,则应继续等待.

When the condition variable is notified, a timeout expires, or a spurious wakeup occurs, the thread is awakened, and the mutex is atomically reacquired. The thread should then check the condition and resume waiting if the wake up was spurious.

此外,在通知条件变量时,如果需要保留侍者FIFO顺序,则必须保留互斥体.

Also, when notifying a condition variable the mutex must be held if waiter FIFO order needs to be preserved.

修复:

int main()
{
    std::condition_variable cv;
    std::mutex cv_m;
    int x = 0;
    bool start = false;

    auto thread_fn = [&]{
        std::unique_lock<std::mutex> lk(cv_m);
        while(!start)
            cv.wait(lk);
        std::cout << "t1 x:" << x++ << std::endl;
    };

    std::thread t1 = std::thread(thread_fn);
    std::thread t2 = std::thread(thread_fn);
    std::thread t3 = std::thread(thread_fn);
    std::thread t4 = std::thread(thread_fn);
    std::thread t5 = std::thread(thread_fn);

    std::cout << "STARTING" << std::endl;
    {
        std::unique_lock<std::mutex> lock(cv_m);
        start = true;
        cv.notify_all();
    }

    t1.join();
    t2.join();
    t3.join();
    t4.join();
    t5.join();
    std::cout << "DONE" << std::endl;
}

这篇关于延迟的线程启动-通知所有未唤醒所有线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆