Tenemos la mejor respuesta que hallamos en línea. Nosotros queremos que te resulte útil y si puedes compartir algo que nos pueda ayudar a crecer hazlo con total libertad.
Solución:
A menudo, las colas de eventos se implementan como un patrón de diseño de comandos:
En la programación orientada a objetos, el patrón de comando es un patrón de diseño en el que se utiliza un objeto para representar y encapsular toda la información necesaria para llamar a un método en un momento posterior. Esta información incluye el nombre del método, el objeto que posee el método y los valores de los parámetros del método.
En C++, el objeto que posee el método y los valores para los parámetros del método es un funtor nulo (es decir, un funtor que no acepta argumentos). Se puede crear usando boost::bind()
o C++11 lambdas y envuelto en boost::function
.
Aquí hay un ejemplo minimalista de cómo implementar una cola de eventos entre múltiples subprocesos de productores y múltiples consumidores. Uso:
void consumer_thread_function(EventQueue::Ptr event_queue)
try
for(;;)
EventQueue::Event event(event_queue->consume()); // get a new event
event(); // and invoke it
catch(EventQueue::Stopped&)
void some_work(int n)
std::cout << "thread " << boost::this_thread::get_id() << " : " << n << 'n';
boost::this_thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds(500));
int main()
some_work(1);
// create an event queue that can be shared between multiple produces and multiple consumers
EventQueue::Ptr queue(new EventQueue);
// create two worker thread and pass them a pointer to queue
boost::thread worker_thread_1(consumer_thread_function, queue);
boost::thread worker_thread_2(consumer_thread_function, queue);
// tell the worker threads to do something
queue->produce(boost::bind(some_work, 2));
queue->produce(boost::bind(some_work, 3));
queue->produce(boost::bind(some_work, 4));
// tell the queue to stop
queue->stop(true);
// wait till the workers thread stopped
worker_thread_2.join();
worker_thread_1.join();
some_work(5);
Salidas:
./test
thread 0xa08030 : 1
thread 0xa08d40 : 2
thread 0xa08fc0 : 3
thread 0xa08d40 : 4
thread 0xa08030 : 5
Implementación:
#include
#include
#include
#include
#include
#include
#include
class EventQueue
public:
typedef boost::intrusive_ptr Ptr;
typedef boost::function Event; // nullary functor
struct Stopped ;
EventQueue()
: state_(STATE_READY)
, ref_count_(0)
void produce(Event event)
boost::mutex::scoped_lock lock(mtx_);
assert(STATE_READY == state_);
q_.push_back(event);
cnd_.notify_one();
Event consume()
boost::mutex::scoped_lock lock(mtx_);
while(STATE_READY == state_ && q_.empty())
cnd_.wait(lock);
if(!q_.empty())
Event event(q_.front());
q_.pop_front();
return event;
// The queue has been stopped. Notify the waiting thread blocked in
// EventQueue::stop(true) (if any) that the queue is empty now.
cnd_.notify_all();
throw Stopped();
void stop(bool wait_completion)
boost::mutex::scoped_lock lock(mtx_);
state_ = STATE_STOPPED;
cnd_.notify_all();
if(wait_completion)
// Wait till all events have been consumed.
while(!q_.empty())
cnd_.wait(lock);
else
// Cancel all pending events.
q_.clear();
private:
// Disable construction on the stack. Because the event queue can be shared between multiple
// producers and multiple consumers it must not be destroyed before the last reference to it
// is released. This is best done through using a thread-safe smart pointer with shared
// ownership semantics. Hence EventQueue must be allocated on the heap and held through
// smart pointer EventQueue::Ptr.
~EventQueue()
this->stop(false);
friend void intrusive_ptr_add_ref(EventQueue* p)
++p->ref_count_;
friend void intrusive_ptr_release(EventQueue* p)
if(!--p->ref_count_)
delete p;
enum State
STATE_READY,
STATE_STOPPED,
;
typedef std::list Queue;
boost::mutex mtx_;
boost::condition_variable cnd_;
Queue q_;
State state_;
boost::detail::atomic_count ref_count_;
;
El estándar C++ no aborda los eventos en absoluto. Sin embargo, por lo general, si necesita eventos, está trabajando dentro de un marco que los proporciona (SDL, Windows, Qt, GNOME, etc.) y formas de esperarlos, enviarlos y usarlos.
Aparte de eso, es posible que desee ver Boost.Signals2.
C++11 y Boost tienen variables de condición. Son un medio para que un hilo desbloquee otro que está esperando que ocurra algún evento. El enlace anterior lo lleva a la documentación para std::condition_variable
y tiene un ejemplo de código que muestra cómo usarlo.
Si necesita realizar un seguimiento de los eventos (por ejemplo, las pulsaciones de teclas) y necesita procesarlos de manera FIFO (primero en entrar, primero en salir), entonces tendrá que usar o crear algún tipo de sistema de cola de eventos de subprocesos múltiples, como se sugiere en algunas de las otras respuestas. Las variables de condición se pueden usar como bloques de construcción para escribir su propia cola de productor/consumidor, si elige no usar una implementación existente.
valoraciones y reseñas
Te invitamos a confirmar nuestro trabajo dejando un comentario y dejando una puntuación te damos la bienvenida.