Delayed Thread Start - Notify All Not Waking All Threads

扶醉桌前 提交于 2019-12-30 11:29:45

问题


attempting:

To do a delayed start on multiple threads.

problem:

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

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)

asking:

  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?

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

code:

// 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;
}

compiling:

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

running:

./a.out

回答1:


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.

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

Fixes:

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;
}


来源:https://stackoverflow.com/questions/50842073/delayed-thread-start-notify-all-not-waking-all-threads

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!