2011-10-27 2 views
5

블로킹 큐 예제를 사용하고 있습니다.이 웹 사이트에서 얻은 예가 꽤 좋았다고 생각합니다. 이 블로킹 큐는 boost :: mutex를 사용하고 있습니다. 그것은 언젠가 예외를 던지고있다 :boost mutex throwing (홀수?) 예외

terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::system::system_error> >' 

무엇을() : 잘못된 파일 기술자 여기

블로킹 큐 코드입니다 :

#include <boost/thread/mutex.hpp> 
#include <boost/thread/thread.hpp> 
#include <boost/thread/condition_variable.hpp> 
#include <exception> 
#include <list> 
#include <stdio.h> 

struct BlockingQueueTerminate 
    : std::exception 
{}; 

namespace tools { 
    template<class T> 
    class BlockingQueue 
    { 
    private: 
    boost::mutex mtx_; 
    boost::condition_variable cnd_; 
    std::list<T> 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; 
    } 
    }; 
} 

누구나 발견 할 수 잘못 여기서 뭐하는거야가? 나는 하루 종일 그것을 헛되이 알아 내려고 노력했기 때문에. 나는 그것을보기 위해 외부의 눈이 필요하다고 생각한다. 댓글을 찾아보십시오 '// 예외가 발생했습니다!' 정확하게 문제가 발생하는지 확인하십시오.

편집 1 :

컨텍스트 : 나는 MySQL의 비동기 랩퍼를 작성하기 위해이 차단 큐를 사용하고 있습니다.

여기 여기 내 MySQL.hh

#ifndef MYSQL_HH_ 
# define MYSQL_HH_ 
# include <boost/asio.hpp> 
# include <boost/thread.hpp> 
# include <boost/function.hpp> 
# include <mysql++/mysql++.h> 
# include <queue> 
# include "async_executor.hh" 
# include "BlockingQueue.hh" 

class t_mysql_event { 
public: 
    t_mysql_event(std::string query, boost::function<void(mysqlpp::StoreQueryResult)> cb) : 
    m_query(query), m_store_cb(cb), m_store_bool(true) {} 

    t_mysql_event(std::string query, boost::function<void()> 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<void(mysqlpp::StoreQueryResult)> m_store_cb; 
    boost::function<void()>    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<void()> cb); 
    void store(std::string query, boost::function<void(mysqlpp::StoreQueryResult)> 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<void()> cb, mysqlpp::Connection& conn); 
    void async_store(std::string query, boost::function<void(mysqlpp::StoreQueryResult)> cb, mysqlpp::Connection& conn); 

    void retreive(); 

    private: 
    tools::async_executor   executor; 
    boost::asio::io_service&  parent_io; 
    boost::asio::strand   m_strand; 
    tools::BlockingQueue<t_mysql_event*> m_events; 
    std::queue<mysqlpp::Connection*> m_stack; 
    }; 
} 

#endif //MYSQL_HH_ 

년대 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<void()> cb) { 
    m_events.put(new t_mysql_event(query, cb)); 
    } 

    void MySQL::store(std::string query, boost::function<void(mysqlpp::StoreQueryResult)> 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<void()> 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<void(mysqlpp::StoreQueryResult)> 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)); 
    } 
} 

:

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

더 많은 정보에 대한 몇 가지 요청에 응답 할 것을 기대 .. .

웃긴 것 :

_mysql을 pools :: MySQL :: get_instance()로 대체하면 충돌이 발생하지 않습니다. 하지만 훨씬 더 중요 아래에서 오류가 의심 ... 큐가 이미 파괴하지만 그 put 메소드를 호출하려고 할 경우이 예외가 발생 할 수 있습니다

+0

게시하지 않은 것이 아니라이 코드가 맞습니까? –

+0

예 예외가이 지점에서 정확하게 발생하고 있음을 확신합니다. 나는 gdb와 많은 std :: cout을 사용하여 물어보기 전에 확신했다. – TheSquad

+0

이상하게 들리지만, 생성자가 예외를 throw 할 수 있다고 생각하지 않습니다. http://www.boost.org/doc/libs/1_37_0/doc/html/boost/interprocess/scoped_lock.html#id2914282-bb –

답변

0

. 중단 점 (또는 print 문)을 대기열 소멸자에 넣음으로써이를 검사하십시오.

+0

싱글 톤 클래스의 속성으로서 객체이기 때문에 파괴되지 않습니다. 네가 그걸 몰랐다고 진실이야. 내 게시물에 더 많은 정보를 추가했습니다. – TheSquad

+0

@Andy T : 정말 예외가 발생합니까? 나는 그것이 segfault하게 될 것이라고 생각한다. – Atmocreations

+0

@Atmocreations boost :: mutex 코드가 유효하지 않은 상태를 감지하면 예외를 throw 할 수 있습니다. 객체 주소는 여전히 객체가 삭제 된 후에도 프로세스에 매핑 된 유효한 주소 일 수 있습니다. 이 경우 seg-fault가 발생하지 않습니다. – selalerer