使用 Poco:Condition 唤醒两个线程

Waking-up two threads with a Poco:Condition

在 Windows 7(64 位)下使用来自 MSYS2 的 Poco 1.9.0-1。

我有一个线程,发出三次 Poco:Condition 信号,休眠 300 毫秒。

我有两个线程使用两个不同的 类 EvListenerA 和 EvListenerB,它们从 Poco::Runnable 扩展而来,并且它们正在等待相同的 Poco::Condition 以显示带有 [=34= 的消息].

对于第一个和第二个信号,没有问题,但是当第三个信号启动时,只有线程 EvListenerA 正确捕获它。

这是代码:

/*
 * main.cpp
 *
 *  Created on: 6 jun. 2019
 *      Author: ccortiz
 */

#include <Poco/Thread.h>
#include <Poco/Runnable.h>
#include <Poco/Condition.h>
#include <iostream>
using namespace std;

Poco::Condition condicion;
Poco::Mutex     mutex;

class GenEvents:public Poco::Runnable{
public:
    void run(){
        cout << "Launching GenEvents!" << endl;

        for (Poco::UInt32 i=0; i<3; i++){
            cout << "[GenEvents] Event_" << i << endl;
            condicion.broadcast();
            Poco::Thread::sleep(300); //Wait 300ms.
        }
        cout << "Ending GenEvents!" << endl;
    }
};

class EvListenerA:public Poco::Runnable{
public:
    void run(){
        cout << "Launching EvListenerA!" << endl;

        for (Poco::UInt32 i=0; i<3; i++){
            condicion.wait(mutex);
            cout << "   [EvListenerA] Receiving Event_" << i << endl;
        }
        cout << "Ending EvListenerA!" << endl;
    }
};

class EvListenerB:public Poco::Runnable{
public:
    void run(){
        cout << "Launching EvListenerB!" << endl;

        for (Poco::UInt32 i=0; i<3; i++){
            condicion.wait(mutex);
            cout << "   [EvListenerB] Receiving Event_" << i << endl;
        }
        cout << "Ending EvListenerB!" << endl;
    }
};

int main(void){
    Poco::Thread th1; //Hilo que genera 3 eventos.
    Poco::Thread th2; //Hilo que espera 3 eventos.
    Poco::Thread th3; //Hilo que espera 3 eventos.

    GenEvents  genEvents;  //Objeto que implementa el hilo generador de eventos.
    EvListenerA evListenerA; //Objeto que implementa el hilo receptor de eventos.
    EvListenerB evListenerB; //Objeto que implementa el hilo receptor de eventos.

    th2.start(evListenerA);
    th3.start(evListenerB);
    Poco::Thread::sleep(500); //Espera de medio segundo.

    th1.start(genEvents);

    th1.join();
    th2.join();
    th3.join();
}

这是程序输出:

Launching EvListenerB!
Launching EvListenerA!
Launching GenEvents!
[GenEvents] Event_0
   [EvListenerB] Receiving Event_0
   [EvListenerA] Receiving Event_0
[GenEvents] Event_1
   [EvListenerA] Receiving Event_1
   [EvListenerB] Receiving Event_1
[GenEvents] Event_2
   [EvListenerA] Receiving Event_2
Ending EvListenerA!
Ending GenEvents!

为什么我的输出中没有“[EvListenerB] Receiving Event_2”?

EvListenerB 和 Event_2 发生了什么?

有什么想法吗?谢谢

嗯,对我来说这是未定义的行为。参考文献中明确指出 ConditionMutexFastMutex 一起使用。当wait被调用时mutex必须被锁定! - 您的代码中缺少它。

引用自reference

A Condition object is always used in conjunction with a Mutex (or FastMutex) object.

Unlocks the mutex (which must be locked upon calling wait()) and waits for the given time until the Condition is signalled.

The given mutex will be locked again upon successfully leaving the function, even in case of an exception.

所以如果你想看到期望的输出,你必须调用 lock/unlock 到 mutex:

    for (Poco::UInt32 i=0; i<3; i++)
    {
        mutex.lock();  // <--- lock mutex
        condicion.wait(mutex);
        cout << "   [EvListenerA] Receiving Event_" << i << endl;
        mutex.unlock(); // <--- unlock
    }

EvListenerAEvListenerB 类 进行相同的更改。

首先你要锁定互斥体。然后 wait 被调用,它解锁 mutex 并且我们等待直到 condition 发出信号,然后 wait returns 并且互斥锁再次被锁定(在从 [ 返回之前=14=]).在离开 for 循环迭代的范围之前 unlock 被调用。