mutex throwing (odd?) istisnasını artır

Bu web sitesinden aldığım engelleme sırasını kullanıyorum, oldukça güzel olduğunu düşünüyorum. Bu engelleme sırası, boost :: mutex kullanıyor. Bazen bir istisna atıyor:

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

what (): Bozuk dosya tanıtıcısı

İşte Engelleme Kuyruğu kodu:

#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;
    }
  };
}

Burada neyin yanlış gittiğini herkes anlayabilir mi? çünkü bütün günü boş yere çözmeyi denedim. Sanırım görmek için dışarıdan bir göze ihtiyacım var. Yoruma bakın '// İstisna burada atıldı!' tam olarak sorunun nerede olduğunu görmek için.

DÜZEN 1:

Bağlam: Bir MySQL async sarıcı oluşturmak için bu engelleme sırasını kullanıyorum.

İşte benim 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_

İşte 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));
   }
}

Sonradan :

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;
};

Daha fazla bilgi için bazı isteklere cevap vereceğini umuyoruz ...

Komik şey :

Her _mysql'yi havuzlar ile değiştirirsem :: MySQL :: get_instance() Bulamıyorum. Ama bunun altında daha önemli bir hata olduğunu sanıyorum ...

5
Buraya istisna getirilebilse de, hata aslında burada olmayabilir. Belki başka bir yerde sınıfı yanlış kullanıyorsunuz, hatta hafızanızı mı yoksa yığınınızı mı atıyorsunuz? ....
katma yazar CygnusX1, kaynak
Bu garip, çünkü kurucuların bir istisna atamayacağını düşünmüyorum: boost.org/doc/libs/1_37_0/doc/html/boost/interprocess/…
katma yazar BЈовић, kaynak
Bu kodun olduğundan emin değil misin, göndermediğin şey değil mi?
katma yazar BЈовић, kaynak
Valgrind veya benzeri araçları denemelisiniz, eminim ki bazı kullanımdan sonra kullanıma sunacaklar.
katma yazar PlasmaHH, kaynak
@TheSquad: o zaman belki de kaynak kodda kazma deneyin hangi değişken değerleri istisna neden ve orijini geri izlemek, belki de gdb ters hata ayıklama ile.
katma yazar PlasmaHH, kaynak
@TheSquad Lütfen sorunuzu sorunu belirten bir minimal olarak eksiksiz bir örnekle düzenleyin. Göndermiş olduğunuz kodda açıkça yanlış bir şey yoktur. En azından, istisnanın atıldığı yığın izlemeyi dahil edin. Diğer yorumların da belirttiği gibi, hatanın programınızın başka bir yerinde olduğundan şüpheleniyorum.
katma yazar Sam Miller, kaynak
@TheSquad örnek kodunuz minimal olarak tamamlanmamıştır. Açıkladığınız sorunu yeniden üretmek için derleyebildiğimiz bir şeyi yayınlayarak size yardımcı olmamıza yardımcı olun.
katma yazar Sam Miller, kaynak
@PlasmaHH: Kullanılan Valgring Eletric-çit, bildiğim her şey ... gerçekten biraz özel bir istisna gibi görünüyor ...
katma yazar TheSquad, kaynak
@Sam Miller: "Asgari düzeyde tamamlanmış" bir örnekte asap olacak, maalesef tam olarak ifşa edemeyeceğim şu anki projem kadar olmayacak. Umarım sorunu yeniden oluşturabilirim.
katma yazar TheSquad, kaynak
@Sam Miller: Buyurun, umarım benim hata bulmak için yeterli bilgi
katma yazar TheSquad, kaynak
@ CygnusX1 Yanlış kullandığımı sanmıyorum, söyle bana ... daha fazla bilgi editörle yayınla
katma yazar TheSquad, kaynak
Özel durumun yapıcıdan gönderildiğini, ancak büyük olasılıkla destek :: mutex nesnesinden emin değilim. Dediğin gibi, garip, başlığa koymamın sebebi (garip?)
katma yazar TheSquad, kaynak
Evet, kesinlikle istisnanın bu noktadan tam olarak attığından eminim. Ben sormadan önce emin olmak için gdb ve bir sürü std :: cout kullandım.
katma yazar TheSquad, kaynak

1 cevap

Bu istisna, sıra zaten silindiyse atılabilir ancak put yöntemini çağırmaya çalışırsınız. Sıra yıkıcıya bir kesme noktası (veya baskı ifadesi) koyarak bunu kontrol edin.

0
katma
@Andy T: Gerçekten bir istisna atar mıydı? Sanırım segfault yapmayı tercih ederim.
katma yazar Atmocreations, kaynak
@TheSquad Belki de bir veri kesme noktası koymak ve erişildiğinde hata ayıklayıcısında görmek deneyin.
katma yazar selalerer, kaynak
@TheSquad MyClass :: _ MySQL üyesinden bahsediyordum, belki de taşınıyor.
katma yazar selalerer, kaynak
@TheSquad Belki bir yerde _mysql taşınır ve get_instance() kullanarak doğru adresi almaya devam ederken geçersiz bir adres döndürür.
katma yazar selalerer, kaynak
@Atmocreations Destek :: muteks kodu geçersiz bir durum tespit ederse, bir istisna atabilir. Nesne adresi, nesne silindikten sonra bile süreçle eşlenen geçerli adresler olabilir. Bu durumda, herhangi bir seg-fault oluşmayacaktır.
katma yazar selalerer, kaynak
@selalerer: bunu zaten yaptım, gdb bana doğru adresi döndürür ve nesne gdb'den doğru bir şekilde erişilebilir.
katma yazar TheSquad, kaynak
@selalerer: İkinci kez ayarlandığı yer yok. Sadece kurucuda. Daha sonra sadece _mysql-> ile erişirim
katma yazar TheSquad, kaynak
@selalerer: MySQL nesnesi sadece bir create_instance (io_service) ile main.cc üzerinde yaratılır, get_instance() sadece create_instance tarafından oluşturulan örneği döndürür. Sadece main.cc'de çağrıldığı için (başka bir yere koymadığımı kontrol ettim) bu taşma olamaz.
katma yazar TheSquad, kaynak
Tek bir sınıfta öznitelik olarak bir nesne olduğu için yok değildir. Doğru bilmiyordun. Gönderiimde daha fazla bilgi ekledim.
katma yazar TheSquad, kaynak