2010-09-16 14 views
11

Soy un recién llegado a la biblioteca de Boost, y estoy tratando de implementar un simple productor y los hilos de consumo que operan en una cola compartida. Mi ejemplo de implementación es el siguiente:Uso de boost :: lock_guard para el bloqueo simple de datos compartidos

#include <iostream> 
#include <deque> 
#include <boost/thread.hpp> 

boost::mutex mutex; 
std::deque<std::string> queue; 

void producer() 
{ 
    while (true) { 
     boost::lock_guard<boost::mutex> lock(mutex); 

     std::cout << "producer() pushing string onto queue" << std::endl; 

     queue.push_back(std::string("test")); 
    } 
} 

void consumer() 
{ 
    while (true) { 
     boost::lock_guard<boost::mutex> lock(mutex); 

     if (!queue.empty()) { 
      std::cout << "consumer() popped string " << queue.front() << " from queue" << std::endl; 

      queue.pop_front(); 
     } 
    } 
} 

int main() 
{ 
    boost::thread producer_thread(producer); 
    boost::thread consumer_thread(consumer); 

    sleep(5); 

    producer_thread.detach(); 
    consumer_thread.detach(); 

    return 0; 
} 

Este código se ejecuta como espero, pero cuando main salidas, consigo

/usr/include/boost/thread/pthread/mutex.hpp:45:  
    boost::mutex::~mutex(): Assertion `!pthread_mutex_destroy(&m)' failed. 
consumer() popped string test from queue 
Aborted 

(no estoy seguro si la salida de consumer es relevante en ese posición, pero lo he dejado en.)

¿Estoy haciendo algo mal en mi uso de Boost?

Respuesta

8

Dale a tus hilos (productor & consumidor) el objeto mutex y luego sepáralos. Se supone que corren para siempre. Luego sale de su programa y el objeto mutex ya no es válido. Sin embargo, sus hilos aún intentan usarlo, no saben que ya no es válido. Si hubieras usado la definición de NDEBUG, hubieras obtenido un microbomba.

¿Está tratando de escribir una aplicación de daemon y esta es la razón para separar los hilos?

+0

No estoy tratando de escribir ningún tipo de aplicación en particular. Solo estoy tratando de familiarizarme con la biblioteca Boost.Thread. Las llamadas a 'detach' se realizaron durante una sesión de depuración rápida; el comportamiento es idéntico si los elimino.Inicialmente sospeché que los hilos debían detenerse antes de que el programa saliera, de ahí la llamada 'detach'. – kfb

+7

No salga inmediatamente de la rosca principal y no separe el consumidor y el productor. Espere en el hilo principal hasta que el consumidor y el productor trabajen. Y cuando terminen, únete a ellos. Y luego salir de la principal. –

+0

Eso tiene sentido, y detiene la afirmación, ¡gracias! – kfb

9

Un poco fuera de tema pero relevante imo (... espera llamas en los comentarios).

El modelo de consumo aquí es muy codicioso, haciendo bucles y verificando continuamente los datos en la cola. Será más eficiente (perderá menos ciclos de CPU) si tiene sus subprocesos de consumo activados de manera determinista cuando los datos están disponibles, usando señalización entre subprocesos en lugar de este ciclo de bloqueo y visualización. Piénselo de esta manera: mientras la cola está vacía, este es esencialmente un círculo cerrado que solo se rompe por la necesidad de adquirir el bloqueo. ¿No es ideal?

void consumer() 
{ 
    while (true) { 
     boost::lock_guard<boost::mutex> lock(mutex); 

     if (!queue.empty()) { 
      std::cout << "consumer() popped string " << queue.front() << " from queue" << std::endl; 

      queue.pop_front(); 
     } 
    } 
} 

Entiendo que usted está aprendiendo, pero yo no aconsejaría el uso de esto en el código 'real'. Para aprender la biblioteca, está bien. Para su crédito, este es un ejemplo más complejo que el necesario para comprender cómo usar lock_guard, ¡así que apunta alto!

Finalmente, lo más probable es construir (o mejor si está disponible, reutilizar) código para una cola que avisa a los trabajadores cuándo deben trabajar y luego usará lock_guard dentro de sus hilos de trabajo para mediar en los accesos a datos compartidos .

+0

información fuera del tema, pero sin duda útil, gracias! Estoy de acuerdo en que este es un consumidor muy codicioso, pero esto se derivó de una prueba anterior en la que no había sincronización y yo estaba tratando de alentar al programa para que se bloqueara :) – kfb

5

Cuando sale main, se destruyen todos los objetos globales. Sus hilos, sin embargo, continúan ejecutándose. Por lo tanto, termina con problemas porque los hilos están accediendo a un objeto eliminado.

La línea inferior es que debe terminar los hilos antes de salir. Lo único que debes hacer es esperar que el programa principal espere (usando un boost::thread::join) hasta que los hilos hayan terminado de ejecutarse. Es posible que desee proporcionar alguna forma de señalizar los hilos para que terminen de ejecutarse y ahorren por esperar demasiado tiempo.

El otro problema es que el hilo del consumidor continúa ejecutándose incluso cuando no hay datos. Es posible que desee esperar en un boost::condition_variable hasta que se indique que hay nuevos datos.

Cuestiones relacionadas