Пробуждение двух ниток с Poco: Состояние - PullRequest
0 голосов
/ 06 июня 2019

с использованием Poco 1.9.0-1 из MSYS2 под Windows 7 (64 бита).

У меня есть один поток, трижды сигнализирующий о 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?

Есть идеи?Спасибо

1 Ответ

1 голос
/ 06 июня 2019

Хм, для меня это неопределенное поведение.Ссылка ясно указывает, что Condition используется вместе с Mutex или FastMutex.Когда wait вызывается, mutex должен быть заблокирован!- он отсутствует в вашем коде.

Цитаты из ссылка :

Объект Condition всегда используется вместе с объектом Mutex (или FastMutex).

и

Разблокирует мьютекс (который должен быть заблокирован при вызове wait ()) и ожидает в течение заданного времени, пока не будет сообщено Условие.

Данный мьютекс будет снова заблокирован при успешном выходе из функции, даже в случае исключения.

Так что, если вы хотите увидеть запрошенный вывод, вы должны вызвать блокировку / разблокировку для мьютекса:

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

сделать то же самое для классов EvListenerA и EvListenerB.

Сначала вы блокируете мьютекс.Затем вызывается wait, разблокируется mutex, и мы ждем, пока не будет сигнализировано condition, затем возвращается wait и мьютекс снова блокируется (перед возвратом из wait).Перед выходом за рамки цикла вызывается итерация unlock.

...