C++ 在boost中等待多个条件变量?

C++ 在boost中等待多个条件变量?,c++,boost,multithreading,C++,Boost,Multithreading,我正在寻找一种等待多个条件变量的方法。 例如: boost::condition_variable cond1; boost::condition_variable cond2; void wait_for_data_to_process() { boost::unique_lock<boost::mutex> lock(mut); wait_any(lock, cond1, cond2); //boost only provides cond1.wa

我正在寻找一种等待多个条件变量的方法。 例如:

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

void wait_for_data_to_process()  
{  
    boost::unique_lock<boost::mutex> lock(mut);

    wait_any(lock, cond1, cond2); //boost only provides cond1.wait(lock);

    process_data();
}
boost::条件变量cond1;
boost::条件变量cond2;
void wait_for_data_to_process()
{  
boost::唯一锁定(mut);
wait_any(lock,cond1,cond2);//boost只提供cond1.wait(lock);
处理_数据();
}
在条件变量中也可以这样。如果没有,还有其他解决方案吗

谢谢


我不确定Boost库,但您可以使用函数来等待多个内核对象。看看这是否有帮助。

我不相信你可以用boost::thread做这样的事情。可能是因为POSIX条件变量不允许这种类型的构造。当然,Windows有aJ发布的WaitForMultipleObjects,如果您愿意将代码限制为Windows同步原语,这可能是一个解决方案

另一个选择是使用更少的条件变量:只要有一个条件变量,当任何“有趣”的事情发生时,您就可以触发它。然后,在任何时候您想要等待,您运行一个循环,检查您感兴趣的特定情况是否出现,如果没有出现,则返回等待条件变量。无论如何,您都应该在这样的循环中等待这些条件变量,因为条件变量等待会受到虚假唤醒的影响(来自boost::thread docs,emphasis mine):

无效等待(boost::unique_lock&lock)


效果:

自动调用
lock.unlock()
并阻止当前线程。当调用
this->notify_one()
this->notify_all()
或错误地通知时,线程将解除阻止

正如Managu指出的,首先使用多种条件可能不是一个好的解决方案。您想做的应该可以使用信号量来实现。

正如Managu已经回答的那样,您可以使用相同的条件变量并检查while循环中的多个“事件”(bool变量)。但是,对这些bool变量的并发访问必须使用condvar使用的相同互斥锁进行保护

由于我已经为一个相关的应用程序输入了这个代码示例,因此我将在这里重新发布它:

boost::condition_variable condvar;
boost::mutex mutex;
bool finished1 = false;
bool finished2 = false;

void longComputation1()
{
    {
        boost::lock_guard<boost::mutex> lock(mutex);
        finished1 = false;
    }
    // Perform long computation
    {
        boost::lock_guard<boost::mutex> lock(mutex);
        finished1 = true;
    }
    condvar.notify_one();
}

void longComputation2()
{
    {
        boost::lock_guard<boost::mutex> lock(mutex);
        finished2 = false;
    }
    // Perform long computation
    {
        boost::lock_guard<boost::mutex> lock(mutex);
        finished2 = true;
    }
    condvar.notify_one();
}

void somefunction()
{
    // Wait for long computations to finish without "spinning"
    boost::lock_guard<boost::mutex> lock(mutex);
    while(!finished1 && !finished2)
    {
        condvar.wait(lock);
    }

    // Computations are finished
}
boost::条件变量condvar;
互斥互斥;
bool finished1=假;
bool finished2=假;
void long1()
{
{
boost::lock_guard lock(互斥锁);
finished1=假;
}
//执行长时间计算
{
boost::lock_guard lock(互斥锁);
finished1=真;
}
condvar.notify_one();
}
void long2()
{
{
boost::lock_guard lock(互斥锁);
finished2=假;
}
//执行长时间计算
{
boost::lock_guard lock(互斥锁);
finished2=真;
}
condvar.notify_one();
}
void函数()
{
//等待长时间的计算完成而不“旋转”
boost::lock_guard lock(互斥锁);
而(!finished1&!finished2)
{
等待(锁);
}
//计算完成了
}

对多个事件使用相同的条件变量在技术上是可行的,但不允许封装。所以我尝试创建一个支持它的类尚未测试它也不支持
notify_one()
,因为我还没有弄清楚如何实现它

#pragma once

#include <condition_variable>
#include <unordered_set>

// 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<std::mutex>& 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<std::mutex>& loc, std::vector<std::reference_wrapper<multi_condition_variable>> 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<std::mutex> lock(_othersMutex);
        _others.insert(cv);
    }

    void removeOther(std::condition_variable* cv)
    {
        // Note that *this may have been destroyed at this point.
        std::lock_guard<std::mutex> lock(_othersMutex);
        _others.erase(cv);
    }

    // The condition variable.
    std::condition_variable _condition;

    // When notified, also notify these.
    std::unordered_set<std::condition_variable*> _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<boost::mutex> lock(mut);
//
//      multi_condition_variable::wait_any(lock, {cond1, cond2});
//
//      process_data();
//  }
#pragma一次
#包括
#包括
//这类似于“条件变量”,但您可以等待多个“多条件变量”。
//在内部,它通过为每个“wait_any()”创建一个新的“condition_variable”并注册来工作
//它与目标'multi_condition_variable'一起运行。调用'notify_all()'时,主'condition_'变量`
//以及由“wait\u any()”创建的所有临时“condition\u变量”。
//
//有两个警告:
//
//  1. 如果有任何线程正在'wait()`ing,则不能调用析构函数。这很难做到,但是
//无论如何,它与'std::wait_condition'相同。
//
//  2. 没有'notify_one()`。你几乎可以实现这一点,但这是我能想到的唯一方法
//这是为了添加一个表示等待次数的'atomic_int'。不幸的是,没有办法
//以原子方式递增它,然后等待。
类多条件变量
{
公众:
多条件变量()
{
}
//请注意,只有在没有线程等待此条件变量时,才可以安全地调用析构函数。
~multi_条件_变量()
{
}
//通知所有调用wait()的线程以及包含此实例的所有wait_any()。
void notify_all()
{
_条件。通知所有人();
对于(自动o:_其他)
o->notify_all();
}
//等待notify_all被调用,或者虚假的唤醒。
无效等待(标准::唯一锁定和锁定)
{
_等待条件(loc);
}
//等待调用'cvs'中的任何notify_all(),或虚假唤醒。
静态void wait_any(std::unique_lock&loc,std::vector cvs)
{
std::条件变量c;
用于(多条件变量&cv:cvs)
cv.addOther(&c);
c、 等待(loc);
用于(多条件变量&cv:cvs)
cv.removeOther(&c);
}
私人:
void addOther(标准::条件变量*cv)
{
标准:锁和防护锁(_othersMutex);
_其他。插入(cv);
}
void removeOther(标准::条件变量*cv)
{
//请注意,*此时可能已被销毁。
标准:锁和防护锁(_othersMutex);
_其他。删除(cv);
}
//条件变量。
std::条件\变量\条件;
//收到通知后,也要通知这些人。
std::无序集(其他);
//互斥以保护对他人的访问。
std::mutex _othersMutex;
};
//示例用法:
//
//多条件变量cond1;
//多条件变量cond2;
//
//void wait_for_data_to_process()
//  {
#pragma once

#include <condition_variable>
#include <unordered_set>

// 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<std::mutex>& 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<std::mutex>& loc, std::vector<std::reference_wrapper<multi_condition_variable>> 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<std::mutex> lock(_othersMutex);
        _others.insert(cv);
    }

    void removeOther(std::condition_variable* cv)
    {
        // Note that *this may have been destroyed at this point.
        std::lock_guard<std::mutex> lock(_othersMutex);
        _others.erase(cv);
    }

    // The condition variable.
    std::condition_variable _condition;

    // When notified, also notify these.
    std::unordered_set<std::condition_variable*> _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<boost::mutex> lock(mut);
//
//      multi_condition_variable::wait_any(lock, {cond1, cond2});
//
//      process_data();
//  }