boost mutex throwing (odd?) uitzondering

Ik gebruik een blokkeringsvoorbeeld dat ik van deze website heb gekregen, omdat ik dacht dat het vrij aardig was. Deze blokkeerwachtrij gebruikt boost :: mutex. Soms gooit het een uitzondering:

terminate called after throwing an instance of 'boost::exception_detail::clone_impl >'

what (): Slechte bestandsdescriptor

Hier is de Blocking Queue code:

#include 
#include 
#include 
#include 
#include 
#include 

struct BlockingQueueTerminate
  : std::exception
{};

namespace tools {
  template
  class BlockingQueue
  {
  private:
    boost::mutex mtx_;
    boost::condition_variable cnd_;
    std::list q_;
    unsigned blocked_;
    bool stop_;

  public:
    BlockingQueue()
      : blocked_()
      , stop_()
    {}

    ~BlockingQueue()
    {
      this->stop(true);
    }

    void stop(bool wait)
    {
     //tell threads blocked on BlockingQueue::pull() to leave
      boost::mutex::scoped_lock lock(mtx_);
      stop_ = true;
      cnd_.notify_all();

      if(wait)//wait till all threads blocked on the queue leave BlockingQueue::pull()
    while(blocked_)
      cnd_.wait(lock);
    }

    void put(T t)
    {
      boost::mutex::scoped_lock lock(mtx_); //The exception is thrown here !
      q_.push_back(t);
      cnd_.notify_one();
    }

  T pull()
    {
      boost::mutex::scoped_lock lock(mtx_);
      ++blocked_;
      while(!stop_ && q_.empty())
    cnd_.wait(lock);
      --blocked_;

      if(stop_) {
    cnd_.notify_all();//tell stop() this thread has left
    throw BlockingQueueTerminate();
      }

      T front = q_.front();
      q_.pop_front();
      return front;
    }
  };
}

Kan iedereen zien wat hier fout gaat? omdat ik de hele dag heb geprobeerd het tevergeefs uit te zoeken. Ik denk dat ik een buitenoog nodig heb om het te zien. Zoek naar de opmerking '// De uitzondering is hier gegooid!' om te zien waar het probleem zich precies voordoet.

EDIT 1:

De context: ik gebruik deze blokkeerwachtrij om een ​​MySQL async-wrapper te maken.

Dit is mijn MySQL.hh

#ifndef MYSQL_HH_
# define MYSQL_HH_
# include 
# include 
# include 
# include 
# include 
# include "async_executor.hh"
# include "BlockingQueue.hh"

class t_mysql_event {
public:
  t_mysql_event(std::string query, boost::function cb) :
    m_query(query), m_store_cb(cb), m_store_bool(true) {}

  t_mysql_event(std::string query, boost::function cb) :
    m_query(query), m_exec_cb(cb),  m_store_bool(false) {}

  bool is_store_query() {
    return m_store_bool;
  }

  std::string toString() {
    return m_query;
  }

  std::string                       m_query;
  boost::function  m_store_cb;
  boost::function               m_exec_cb;

private:
  bool                          m_store_bool;
};

namespace pools {
  class MySQL {
  public:
    ~MySQL() {}

    static MySQL* create_instance(boost::asio::io_service& io);

    static MySQL* get_instance();

    void exec(std::string query, boost::function cb);
    void store(std::string query, boost::function cb);

  private:
    MySQL(boost::asio::io_service& io) : executor(io, 100), parent_io(io), m_strand(io)
    {
      for (int i=0; i < 100; ++i) {
    boost::thread(boost::bind(&MySQL::retreive, this));
      }
    }

    void async_exec(std::string query, boost::function cb, mysqlpp::Connection& conn);
    void async_store(std::string query, boost::function cb, mysqlpp::Connection& conn);

    void retreive();

  private:
    tools::async_executor           executor;
    boost::asio::io_service&        parent_io;
    boost::asio::strand         m_strand;
    tools::BlockingQueue    m_events;
    std::queue    m_stack;
  };
}

#endif //MYSQL_HH_

Dit is de MySQL.cc:

#include "MySQL.hh"

static pools::MySQL* _instance = 0;

namespace pools {


  MySQL* MySQL::create_instance(boost::asio::io_service& io) {
    if (!_instance)
      _instance = new MySQL(io);
    return _instance;
  }

  MySQL* MySQL::get_instance() {
    if (!_instance) {
      exit(1);
    }
    return _instance;
  }

  void MySQL::exec(std::string query, boost::function cb) {
    m_events.put(new t_mysql_event(query, cb));
  }

  void MySQL::store(std::string query, boost::function cb) {
    m_events.put(new t_mysql_event(query, cb));
  }

  void MySQL::retreive() {
    mysqlpp::Connection conn("***", "***", "***", "***");
    for(;;) {
      t_mysql_event *event = m_events.pull();
      if (event->is_store_query())
    async_store(event->m_query, event->m_store_cb, conn);
      else
    async_exec(event->m_query, event->m_exec_cb, conn);
      delete event;
    }
  }

  void MySQL::async_exec(std::string query, boost::function cb, mysqlpp::Connection& conn) {
    mysqlpp::Query db_q = conn.query(query.c_str());
    db_q.exec();
    parent_io.post(cb);
  }

  void MySQL::async_store(std::string query, boost::function cb, mysqlpp::Connection& conn) {
    mysqlpp::Query db_q = conn.query(query.c_str());
    mysqlpp::StoreQueryResult res = db_q.store();
    parent_io.post(boost::bind(cb, res));
   }
}

Daarna:

class MyClass {
public:
   MyClass() : _mysql(pools::MySQL::get_instance()) {}

   startQueries();
private:
   void Query1() {
      std::stringstream query("");
      query << "INSERT INTO Table1 ***";
      _mysql->exec(query.str(),
                   boost::bind(&MyClass::Query2, this, _1));
   }
   void Query2() {
      std::stringstream query("");
      query << "INSERT INTO Table2 ***";
      _mysql->exec(query.str(),
                   boost::bind(&MyClass::Query3, this, _1));
   }
   void Query3() {
      std::stringstream query("");
      query << "INSERT INTO Table3 ***";
      _mysql->exec(query.str(),
                   boost::bind(&MyClass::done, this, _1));
   }
   void done() {}
   pools::MySQL *_mysql;
};

In de hoop dat dit zal antwoorden op een verzoek om meer informatie ...

Grappig ding :

Als ik elke _mysql vervang door pools :: MySQL :: get_instance() Ik lijkt niet te crashen. Maar ik vermoed dat er een fout veel belangrijker is dan dat ...

5
Ik zou erop willen wijzen dat hoewel hier een uitzondering kan worden gemaakt, de bug hier misschien niet is. Misschien ergens anders gebruik je de klasse verkeerd, of gooi je zelfs je geheugen of stapel in de war? ....
toegevoegd de auteur CygnusX1, de bron
Dat is raar, want ik denk niet dat constructeurs een uitzondering kunnen maken: boost.org/doc/libs/1_37_0/doc/html/boost/interprocess/…
toegevoegd de auteur BЈовић, de bron
Weet je zeker dat het deze code is en niet degene die je niet hebt geplaatst?
toegevoegd de auteur BЈовић, de bron
Je moet valgrind of soortgelijke tools proberen, ik weet zeker dat ze zullen verschijnen na gebruik.
toegevoegd de auteur PlasmaHH, de bron
@TheSquad: probeer dan misschien in de broncode op te graven welke variabelewaarden die uitzondering veroorzaken en zijn oorsprong terug te volgen, misschien met gdb reverse debugging.
toegevoegd de auteur PlasmaHH, de bron
@TheSquad Bewerk uw vraag met een minimaal volledig voorbeeld waarin het probleem wordt weergegeven. Er is niets duidelijk mis met de code die je hebt gepost. Voeg ten minste het stacktracé toe waar de uitzondering wordt gegenereerd. Zoals andere opmerkingen aangeven, vermoed ik dat de bug ergens anders in uw programma voorkomt.
toegevoegd de auteur Sam Miller, de bron
@TheSquad uw voorbeeldcode is niet minimaal compleet. Help ons om u te helpen door iets te plaatsen dat we kunnen compileren om het probleem dat u beschrijft te reproduceren.
toegevoegd de auteur Sam Miller, de bron
@PlasmaHH: Gebruikte Valgring Eletric-fence, alles wat ik wist ... het lijkt echt een beetje een speciale uitzondering ...
toegevoegd de auteur TheSquad, de bron
@Sam Miller: Zal ​​zo snel mogelijk werken aan een "minimaal compleet" voorbeeld dat helaas niet precies zo zal zijn als mijn huidige project dat ik niet kan onthullen. In de hoop dat ik het probleem kan reproduceren.
toegevoegd de auteur TheSquad, de bron
@Sam Miller: Here you go, Ik hoop dat het genoeg informatie is om mijn fout te vinden
toegevoegd de auteur TheSquad, de bron
@ CygnusX1 Ik denk niet dat ik het verkeerd gebruik, vertel je me ... post bewerkt met meer informatie
toegevoegd de auteur TheSquad, de bron
Ik ben niet zeker of de uitzondering wordt verzonden door de constructor, maar hoogstwaarschijnlijk door het boost :: mutex-object. Zoals je zegt, het is raar, reden waarom ik ervoor kies om (vreemd?) Op de titel te zetten
toegevoegd de auteur TheSquad, de bron
Ja, ik ben er vrij zeker van dat de uitzondering precies van dit punt af komt. Ik heb gdb en veel std :: cout gebruikt voordat ik erom vroeg.
toegevoegd de auteur TheSquad, de bron

1 antwoord

deze uitzondering kan worden gegenereerd als de wachtrij al is vernietigd, maar u probeert de methode put aan te roepen. Controleer dit door een onderbrekingspunt (of afdrukinstructie) in wachtrijvernietiger te plaatsen.

0
toegevoegd
@Andy T: Zou het echt een uitzondering zijn? Ik denk dat het eerder segfault zou zijn.
toegevoegd de auteur Atmocreations, de bron
@TheSquad Probeer er misschien een data-break-point op te zetten en in de foutopsporing te zien wanneer het wordt geopend.
toegevoegd de auteur selalerer, de bron
@TheSquad Ik had het over MyClass :: _ MySQL lid dat misschien overloopt.
toegevoegd de auteur selalerer, de bron
@TheSquad Misschien heb je _mysql ergens overschreden en retourneert het een ongeldig adres, terwijl het gebruik van get_instance() je het juiste adres blijft geven.
toegevoegd de auteur selalerer, de bron
@Amocreations Als de boost :: mutex-code een ongeldige status detecteert, kan deze een uitzondering genereren. Het objectadres kan nog steeds geldige adressen zijn die zijn toegewezen aan het proces, zelfs nadat het object is verwijderd. Als dit het geval is, zal er geen seg-fout optreden.
toegevoegd de auteur selalerer, de bron
@selalerer: al gedaan dat, gdb retourneert me het juiste adres en het object is correct toegankelijk vanaf gdb.
toegevoegd de auteur TheSquad, de bron
@selalerer: Er is geen waar het voor de tweede keer is ingesteld. Alleen op de constructor. Daarna heb ik alleen toegang tot het met _mysql->
toegevoegd de auteur TheSquad, de bron
@selalerer: Het ding is dat het MySQL-object alleen wordt gemaakt op de main.cc met een create_instance (io_service), get_instance() retourneert alleen de instantie die is gemaakt door create_instance. Omdat het alleen in de main.cc wordt genoemd (ik heb gecontroleerd of ik het ergens anders niet heb geplaatst) kan het niet worden overschreden.
toegevoegd de auteur TheSquad, de bron
Het wordt niet vernietigd omdat het een object is als attribuut in een singleton-klasse. Dat wist je echt niet. Ik heb veel meer informatie toegevoegd in mijn bericht.
toegevoegd de auteur TheSquad, de bron