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 ...