如何在Linux上同时等待两个条件?

时间:2012-08-04 02:33:44

标签: c++ c linux pthreads posix

考虑一个系统,其中一堆线程等待某些事务完成(请注意,多个线程可以等待单个事务)。为了完成事务,其中一个线程必须运行一个分派循环。一旦当前正在运行调度循环的线程等待事务完成,其他线程之一必须接管该作业。

在Windows上,这很容易实现:对于每个事务,都会在事务完成时设置手动重置事件。此外,还有一个自动复位事件,在调度循环退出时设置。每个线程同时等待两个事件。事务事件首先发出信号 - 在这种情况下线程退出 - 或循环事件 - 在这种情况下线程运行调度循环。

如何在Linux上实现这一点(或者更好的是,Posix)?目前,我用bool变量替换了上面的事件,我有一个条件变量来表示其中一个变化。然而,在这种安排中,线程虚假地唤醒(每当一个事务完成时,所有线程都被唤醒)。有没有办法更好地实现这个?

2 个答案:

答案 0 :(得分:4)

我可能没有完全清楚您的场景,但我认为您可以为每个事务使用一个条件变量(但仍然只有一个互斥锁)。

当事务结束时,会发出相应的条件变量信号;当调度循环退出时,所有条件变量都会发出信号。

答案 1 :(得分:0)

我可能误解了你的要求。我会为事件创建一个抽象,并有一个事件队列。派生事件将被排队,并且线程正在等待队列非空的条件。 enqueue会在条件变量上产生信号。

struct AnEvent {
    int type_;
    union {
        //...
    };
};

struct EventQ {
    std::mutex m_;
    std::condition_variable c_;
    std::list<AnEvent> q_;

    void enq (const AnEvent &e) {
        std::lock_guard<std::mutex> g(m_);
        bool was_empty = q_.empty();
        q_.push_back(e);
        if (was_empty) c_.notify_one();
    };

    void deq (AnEvent &e) {
        std::lock_guard<std::mutex> g(m_);
        while (q_.empty()) c_.wait(m_);
        e = q_.top();
        q_.pop_front();
        if (!q_.empty()) c_.notify_one();
    }