mardi 21 janvier 2020

How to "orderly wake up" multiple threads waiting on a std::condition_variable

I have a simple implementation of timed waiting on a condition_variable used accross two threads. This is working great and as expected.

Code:
Following is the code. And note that I have taken care of the condition_variable spurious wake up issue mentioned at cppreference

//CondVarWrapper.hpp
#pragma once

#include <mutex>
#include <chrono>
#include <condition_variable>

class CondVarWrapper {
public:
    void Signal() {
        std::unique_lock<std::mutex> unique_lock(mutex);
        cond_var_signalled = true;
        timed_out = false;
        unique_lock.unlock();
        cond_var.notify_one();
    }

    bool WaitFor(const std::chrono::seconds timeout) {
        std::unique_lock<std::mutex> unique_lock(mutex);
        timed_out = true;
        cond_var.wait_for(unique_lock, timeout, [this] {
            return cond_var_signalled;
        });
        cond_var_signalled = false;
        return (timed_out == false);
    }

private:
    bool cond_var_signalled = false;
    bool timed_out  = false;
    std::mutex  mutex;
    std::condition_variable cond_var;
};


// Main.cpp
#include "CondVarWrapper.hpp"

#include <chrono>
#include <iostream>
#include <thread>

int main()
{
   std::cout << "Program starts" << std::endl;
   CondVarWrapper cond_var_wrapper;

   std::thread my_thread = std::thread([&cond_var_wrapper]{
       std::cout << "Thread started" << std::endl;
        if (cond_var_wrapper.WaitFor(std::chrono::seconds(10))) {
            std::cout << "Thread stopped by signal from main" << std::endl;
        } else {
            std::cout << "ERROR: Thread stopping because of timeout" << std::endl;
        }
    });

   std::this_thread::sleep_for(std::chrono::seconds(3));
   // Uncomment following line to see the timeout working
   cond_var_wrapper.Signal();
   my_thread.join();
   std::cout << "Program ends" << std::endl;
}

Question:
But how do I extend this for the case of multiple threads waiting for the condition_variable? Or if there is an example to this in a proper way getting around the spurious wakeup issue?

I know that doing a notify_all can wake up multiple waiting threads but I want to wake the threads in order of their request. The thread which called WaitFor before must be woken before the ones calling later and thus in order of their request.

Probably this needs a std::queue in CondVarWrapper? It would be great if someone could show a basic sample of how to do this properly?

Aucun commentaire:

Enregistrer un commentaire