Ver Mensaje Individual
  #1 (permalink)  
Antiguo 23/02/2015, 11:55
amchacon
 
Fecha de Ingreso: julio-2012
Mensajes: 375
Antigüedad: 11 años, 9 meses
Puntos: 28
Extraño deadlock (C++11)

Estoy implementando una queue safethread. Y me está dando algunos problemas.

Tengo una función wait_pop(), que hace pop en la cola si esta no está vacía. Si la cola está vacía entonces se espera a que llegue un elemento.

Estas son las funciones correspondientes:

Código C++:
Ver original
  1. class queue{
  2.  
  3. //...
  4.  
  5. std::condition_variable Variable;
  6. mutable std::mutex Cerrojo;
  7.  
  8. void waitSomething(std::unique_lock<std::mutex> &e,std::condition_variable &Condicion,
  9.                    bool (queue<T>::*predicado)() const)
  10. {
  11.     while (((*this).*predicado)())
  12.     {
  13.         Condicion.wait(e);
  14.     }
  15. }
  16.  
  17. void consumer_enterprotocol(std::unique_lock<std::mutex> &e)
  18. {
  19.     waitSomething(e,Variable_Push,&queue<T>::empty_nothreadsafe);
  20. }
  21.  
  22. void producer_exitprotocol(std::unique_lock<std::mutex> &e)
  23. {
  24.     e.unlock();
  25.     Variable.notify_one();
  26. }
  27.  
  28. bool empty_nothreadsafe() const noexcept override
  29. {
  30.       return Cola.empty();
  31. }
  32.  
  33. //PUBLIC...
  34.  
  35. void push(const T &elemento)
  36. {
  37.     unique_lock<std::mutex> e(Cerrojo);
  38.     producer_enterprotocol(e);
  39.     Cola.push(elemento);
  40.     producer_exitprotocol(e);
  41. }
  42.  
  43. void wait_pop(T &elemento)
  44. {
  45.     unique_lock<std::mutex> e(Cerrojo);
  46.     consumer_enterprotocol(e);
  47.     pop_nothreadsafe(elemento);
  48.     consumer_exitprotocol(e);
  49. }

Y el código de pruebas:

Código C++:
Ver original
  1. #include <iostream>
  2. #include "STL Threadsafe/queue thread safe.hpp"
  3.  
  4. std::threadsafe::queue<int> Cola;
  5.  
  6. int max = 200;
  7. void hilo()
  8. {
  9.     for (int i = 0;i<max;i++)
  10.     {
  11.         Cola.push(i);
  12.     }
  13. }
  14.  
  15. int main()
  16. {
  17.     int e = 0;
  18.     std::thread t(hilo);
  19.    // std::this_thread::sleep_for(std::chrono::milliseconds(1));
  20.     for (int i = 0;i<max;i++)
  21.     {
  22.         Cola.wait_pop(e);
  23.         std::cout<<e<<std::endl;
  24.     }
  25.     std::cout<<"Fin: "<<Cola.size()<<std::endl;
  26.     t.join();
  27. }

Sin embargo, este código se me queda bloqueado en el wait_pop indefinidamente. Si quito la línea comentada (el sleep) entonces si funciona perfecto. Lo he estado revisando pero caigo en la idea.

Subo el código completo por si alguien quiere compilarlo. El código completo es más complicado que este (lo he simplificado un poquito en el post), los métodos están en lineal_container en vez de queue:
https://dl.dropboxusercontent.com/u/...%20amchacon.7z