waiting for multiple condition variables in boost?

后端 未结 5 1598
没有蜡笔的小新
没有蜡笔的小新 2021-02-05 09:36

I\'m looking for a way to wait for multiple condition variables. ie. something like:

boost::condition_variable cond1;  
boost::condition_variable cond2;

void wa         


        
5条回答
  •  -上瘾入骨i
    2021-02-05 10:03

    Using the same condition variable for multiple events technically works, but it doesn't allow encapsulation. So I had an attempt at making a class that supports it. Not tested yet! Also it doesn't support notify_one() as I haven't worked out how to implement that.

    #pragma once
    
    #include 
    #include 
    
    // This is like a `condition_variable` but you can wait on multiple `multi_condition_variable`s.
    // Internally it works by creating a new `condition_variable` for each `wait_any()` and registering
    // it with the target `multi_condition_variable`s. When `notify_all()` is called, the main `condition_variable`
    // is notified, as well as all the temporary `condition_variable`s created by `wait_any()`.
    //
    // There are two caveats:
    //
    //  1. You can't call the destructor if any threads are `wait()`ing. This is difficult to get around but
    //     it is the same as `std::wait_condition` anyway.
    //
    //  2. There is no `notify_one()`. You can *almost* implement this, but the only way I could think to do
    //     it was to add an `atomic_int` that indicates the number of waits(). Unfortunately there is no way
    //     to atomically increment it, and then wait.
    class multi_condition_variable
    {
    public:
        multi_condition_variable()
        {
        }
    
        // Note that it is only safe to invoke the destructor if no thread is waiting on this condition variable.
        ~multi_condition_variable()
        {
        }
    
        // Notify all threads calling wait(), and all wait_any()'s that contain this instance.
        void notify_all()
        {
            _condition.notify_all();
            for (auto o : _others)
                o->notify_all();
        }
    
        // Wait for notify_all to be called, or a spurious wake-up.
        void wait(std::unique_lock& loc)
        {
            _condition.wait(loc);
        }
    
        // Wait for any of the notify_all()'s in `cvs` to be called, or a spurious wakeup.
        static void wait_any(std::unique_lock& loc, std::vector> cvs)
        {
            std::condition_variable c;
            for (multi_condition_variable& cv : cvs)
                cv.addOther(&c);
            c.wait(loc);
            for (multi_condition_variable& cv : cvs)
                cv.removeOther(&c);
        }
    
    private:
        void addOther(std::condition_variable* cv)
        {
            std::lock_guard lock(_othersMutex);
            _others.insert(cv);
        }
    
        void removeOther(std::condition_variable* cv)
        {
            // Note that *this may have been destroyed at this point.
            std::lock_guard lock(_othersMutex);
            _others.erase(cv);
        }
    
        // The condition variable.
        std::condition_variable _condition;
    
        // When notified, also notify these.
        std::unordered_set _others;
    
        // Mutex to protect access to _others.
        std::mutex _othersMutex;
    };
    
    // Example use:
    //
    //  multi_condition_variable cond1;
    //  multi_condition_variable cond2;
    //
    //  void wait_for_data_to_process()
    //  {
    //      unique_lock lock(mut);
    //
    //      multi_condition_variable::wait_any(lock, {cond1, cond2});
    //
    //      process_data();
    //  }
    

提交回复
热议问题