c++ windows multithreading boost cross-platform

c++ - Equivalente multiplataforma a eventos de Windows



multithreading boost (10)

Como los comentarios están cerrados para mí, tuve que publicar mis comentarios en publicaciones anteriores como respuesta. Pero en realidad no estoy respondiendo.

1) Hay un problema con la solución de @Alan. El código de muestra que proporcionó funciona bien. Pero es diferente de la funcionalidad de eventos de Windows. Cuando se establece un objeto Evento de Windows, cualquier número de llamadas posteriores a WaitForSingleObject vuelve inmediatamente, mostrando que el objeto está en estado señalado. Pero con la solución mutex / condition boost, bar() tiene que notificar la condición para cada foo() llamadas que lo necesiten. Esto hace que la situación sea mucho más difícil para la funcionalidad de eventos de Windows "multiplataforma". notify_all() tampoco puede ayudar.

Por supuesto, esto se resuelve de alguna manera en el código de muestra de @dift_code usando una variable booleana. (Aunque se resiente de un problema de condición de carrera. Considere si SetEvent(...) se llama dead después de while(!evt->m_bool) y antes de evt->m_cond.wait(lock) dentro de un hilo separado. Sin embargo, esto puede resolverse utilizando algunas técnicas de gestión de la condición de carrera para hacer que las dos declaraciones while() y wait() atomic.) Pero tiene su propia deficiencia:

2) También hay un problema con el código de @deft_code al hacer uso de la combinación boost mutex / condition / bool :

Se pueden nombrar objetos de evento en Windows, lo que les permite ser utilizados para sincronizaciones entre procesos. Por ejemplo, el proceso A puede crear un evento con nombre y establecerlo así: SetEvent(hFileIsReady) . Después, cualquiera que sea el número de procesos que esperan que se establezca este evento (llamando así a WaitForSingleObject(hFileIsReady) ) continuará inmediatamente su ejecución normal hasta que el evento se reinicie nuevamente dentro del proceso A mediante ResetEvent(hFileIsReady) .

Pero la combinación mutex / condition / bool no puede permitirse tal funcionalidad. Por supuesto, podemos usar boost named_condition y named_mutex . Sin embargo, ¿qué pasa con la variable booleana que debemos verificar antes de esperar?

Estoy tratando de portar algún código de Windows a Linux, idealmente a través de librerías independientes de la plataforma (por ejemplo, impulsar), sin embargo, no estoy seguro de cómo portar este código de evento.

El bit de código implica dos hilos (vamos a llamarlos A y B). A quiere hacer algo que solo B puede, por lo que envía un mensaje a B, luego espera que B lo haga. En Windows esto se ve algo así como:

void foo();//thread a calls this void bar(HANDLE evt); void foo() { HANDLE evt = CreateEvent(0,FALSE,FALSE,0); bCall(boost::bind(&bar, evt)); WaitForSingleObject(evt,INFINITE); CloseHandle(evt); } void bar(HANDLE evt) { doSomething(); SetEvent(evt); }

Miré la biblioteca boost :: thread, pero parecía no tener nada que hiciera esto, el cierre que pude ver fue el boost :: condition_variable, pero parece que es un medio en combinación con un mutex, que no es el caso aquí.


Creo que un buen equivalente multiplataforma a los eventos win32 es boost::condition , por lo que su código podría verse más o menos así:

void foo() { boost::mutex mtxWait; boost::condition cndSignal; bCall(boost::bind(&bar, mtxWait, cndSignal)); boost::mutex::scoped_lock mtxWaitLock(mtxWait); cndSignal.wait(mtxWait); // you could also use cndSignal.timed_wait() here } void bar(boost::mutex& mtxWait, boost::condition& cndSignal) { doSomething(); cndSignal.notify_one(); }


De Boost.Thread versión 1.47 documentation :

Las clases condition_variable y condition_variable_any proporcionan un mecanismo para que un subproceso espere la notificación de otro subproceso de que una condición particular se ha convertido en verdadera.


En los sistemas compatibles con Posix puede usar Posix IPC. Se utiliza para mensajería entre procesos / entre hilos. Si no recuerdo mal, hay un puerto cygwin disponible.


He hecho (o visto) todo lo siguiente en varias ocasiones para cosas como esta:

Use una variable de condición mutex + a.

Use una tubería, después de haber creado la tubería y pase el extremo de escritura a la barra. Bar luego escribe en la tubería cuando la barra está lista. (Esto incluso funciona en múltiples procesos).

Tener foo encuesta en un booleano (sí, esta es una mala idea).


Para cualquier persona involucrada o que trabaje en portar código C / C ++ nativo de múltiples subprocesos a Linux / Mac, hemos creado una biblioteca de código abierto (licencia MIT) que implementa eventos WIN32 manuales y de reinicio automático sobre pthreads, incluyendo una implementación completa de WaitForSingleObject y WaitForMultipleObjects , por lo que es el único puerto WFMO que conozco disponible en Linux / Mac.

pevents está disponible en GitHub y ha sido bastante probado en la batalla y algunos grandes nombres lo utilizan; también hay un puerto de impulso de pevents flotando por ahí.

El uso de pevents hará que portar código de Windows sea mucho más fácil ya que los paradigmas subyacentes son dramáticamente diferentes entre Windows y las plataformas posix, aunque recomendaría a cualquiera que escriba código multiplataforma que use una biblioteca multihilo multiplataforma existente como impulsar en primer lugar.


Parece que estás buscando mecanizado de ranura de señal. Puedes encontrar uno en:

boost y Qt

ambos crossplatform.

Ejemplo de Qt:

#include <QObject> class Counter : public QObject { Q_OBJECT public: Counter() { m_value = 0; } int value() const { return m_value; } public slots: void setValue(int value); signals: void valueChanged(int newValue); private: int m_value; }; Counter a, b; QObject::connect(&a, SIGNAL(valueChanged(int)), &b, SLOT(setValue(int))); a.setValue(12); // a.value() == 12, b.value() == 12 b.setValue(48); // a.value() == 12, b.value() == 48 void Counter::setValue(int value) { if (value != m_value) { m_value = value; emit valueChanged(value); } }


Podría usar una promesa y un futuro, del hilo de impulso:

#include <boost/thread.hpp> boost::promise<bool> prom; void foo() { auto future = prom.get_future(); auto result = future.wait_for(boost::chrono::milliseconds(1000)); // we get here if (a) 1 second passes or (b) bar sets the promise value if (result==boost::future_status::ready) { /* bar set the promise value */ } if (result==boost::future_status::timeout) { /* 1 second passed without bar setting promise value */ } } void bar() { prom.set_value(true); }


Todas estas respuestas son demasiado complejas, vamos gente, no es tan difícil.

namespace porting { class Event; typedef Event* Event_handle; static const unsigned k_INFINITE = 0xFFFFFFFF; class Event { friend Event_handle CreateEvent( void ); friend void CloseHandle( Event_handle evt ); friend void SetEvent( Event_handle evt ); friend void WaitForSingleObject( Event_handle evt, unsigned timeout ); Event( void ) : m_bool(false) { } bool m_bool; boost::mutex m_mutex; boost::condition m_condition; }; Event_handle CreateEvent( void ) { return new Event; } void CloseHandle( Event_handle evt ) { delete evt; } void SetEvent( Event_handle evt ) { evt->m_bool = true; evt->m_cond.notify_all(); } void WaitForSingleObject( Event_handle evt, unsigned timeout ) { boost::scoped_lock lock( evt->m_mutex ); if( timeout == k_INFINITE ) { while( !evt->m_bool ) { evt->m_cond.wait( lock ); } } else { //slightly more complex code for timeouts } } }// porting void foo() { porting::Event_handle evt = porting::CreateEvent(); bCall( boost::bind(&bar, evt ) ); porting::WaitForSingleObject( evt, porting::k_INFINITE ); porting::CloseHandle(evt); } void bar( porting::Event_handle evt ) { doSomething(); porting::SetEvent(evt); }

Probablemente haya algo más que hacer para que esto funcione por completo, ya que no estoy familiarizado con la semántica de WaitForSingleObject (¿qué ocurre si dos hilos lo llaman al mismo tiempo, qué pasa si el mismo hilo lo llama dos veces). Sin embargo, la solución se verá muy similar a esto.


puedes usar la barrier hilo de refuerzo

#include <boost/thread/thread.hpp> #include <boost/thread/barrier.hpp> #include <iostream> void foo(boost::barrier* b) { std::cout << "foo done" << std::endl; b->wait(); } int main() { std::cout << "start foo" << std::endl; boost::barrier b(2); boost::thread t(&foo, &b); b.wait(); std::cout << "after foo done" << std::endl; t.join(); }