【问题标题】:Waking-up two threads with a Poco:Condition使用 Poco:Condition 唤醒两个线程
【发布时间】:2019-06-06 11:26:06
【问题描述】:

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

我有一个线程,发出 3 次 Poco:Condition 信号,睡眠时间为 300 毫秒。

我有两个线程使用两个不同的类 EvListenerA 和 EvListenerB,它们从 Poco::Runnable 扩展,它们正在等待同一个 Poco::Condition 以显示带有 std::cout 的消息。

使用第一个和第二个信号没有问题,但是当启动第三个信号时,只有线程 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 会发生什么?

有什么想法吗?谢谢

【问题讨论】:

    标签: c++ multithreading poco poco-libraries


    【解决方案1】:

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

    引用reference:

    条件对象总是与互斥体(或 FastMutex) 对象。

    解锁互斥体(必须在调用 wait() 时锁定)并等待 在给定的时间内,直到条件发出信号。

    给定的互斥量将在成功离开后再次被锁定 函数,即使出现异常。

    因此,如果您想看到预期的输出,您必须在互斥体上调用 lock/unlock:

        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 返回并再次锁定互斥锁(在从wait 返回之前)。在离开 for 循环迭代的范围之前 unlock 被调用。

    【讨论】:

    • 我已经尝试过你的想法,它确实有效。谢谢。但是我已经玩了一点......我想正确的方法是为每个evListener附加一个属性互斥锁。这避免了未定义的行为,并且也有效。再次感谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-03
    相关资源
    最近更新 更多