В рамках проекта я пишу функцию регистратора. Эта функция регистратора отправляет электронное письмо, когда программа хочет что-то зарегистрировать. Поскольку случилось так, что SMTP-сервер не отвечал, я решил отправить почту в отдельном потоке. Этот поток читает сообщения из std :: deque, который заполняется функцией регистрации. Поток настраивается следующим образом:
while (!boost::this_thread::interruption_requested())
{
EmailItem emailItem;
{
boost::unique_lock<boost::mutex> lock(mMutex);
while (mEmailBuffer.empty())
mCond.wait(lock);
bufferOverflow = mBufferOverflow;
mBufferOverflow = false;
nrOfItems = mEmailBuffer.size();
if (nrOfItems > 0)
{
emailItem = mEmailBuffer.front();
mEmailBuffer.pop_front();
}
}
if (nrOfItems > 0)
{
bool sent = false;
while(!sent)
{
try
{
..... Do something with the message .....
{
boost::this_thread::disable_interruption di;
boost::lock_guard<boost::mutex> lock(mLoggerMutex);
mLogFile << emailItem.mMessage << std::endl;
}
sent = true;
}
catch (const std::exception &e)
{
// Unable to send mail, an exception occurred. Retry sending it after some time
sent = false;
boost::this_thread::sleep(boost::posix_time::seconds(LOG_WAITBEFORE_RETRY));
}
}
}
}
Функция log () добавляет новое сообщение в двухстороннюю очередь (mEmailBuffer) следующим образом:
{
boost::lock_guard<boost::mutex> lock(mMutex);
mEmailBuffer.push_back(e);
mCond.notify_one();
}
Когда основная программа завершается, вызывается деструктор объекта регистратора. Здесь происходит сбой, приложение вылетает с ошибкой:
/usr/include/boost/thread/pthread/mutex.hpp:45: boost::mutex::~mutex(): Assertion `!pthread_mutex_destroy(&m)' failed.
Деструктор просто вызывает прерывание в потоке, а затем присоединяется к нему:
mQueueThread.interrupt();
mQueueThread.join();
В основной программе я использую несколько разных классов, которые используют ускорение потоковой передачи а также мьютекс, могло ли это вызвать такое поведение? Отсутствие вызова деструктора объекта логгера не приводит к ошибкам, как и использование объекта логгера и бездействие чего-либо.
Я предполагаю, что я делаю что-то очень неправильно, или есть ошибка в библиотеке потоков при использовании нескольких потоки разделены на несколько классов. Кто-нибудь знает, в чем может быть причина этой ошибки?
РЕДАКТИРОВАТЬ: Я сделал, как предлагал @Andy T, и максимально удалил код. Я удалил почти все в функции, которая выполняется в другом потоке. Теперь цепочка выглядит так:
void Vi::Logger::ThreadedQueue()
{
bool bufferOverflow = false;
time_t last_overflow = 0;
unsigned int nrOfItems = 0;
while (!boost::this_thread::interruption_requested())
{
EmailItem emailItem;
// Check for new log entries
{
boost::unique_lock<boost::mutex> lock(mMutex);
while (mEmailBuffer.empty())
mCond.wait(lock);
}
}
}
Проблема все еще сохраняется. Однако поиск проблемы показал мне нечто отличное от исходного кода:
#0 0x00007ffff53e9ba5 in raise (sig=<value optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1 0x00007ffff53ed6b0 in abort () at abort.c:92
#2 0x00007ffff53e2a71 in __assert_fail (assertion=0x7ffff7bb6407 "!pthread_mutex_lock(&m)", file=<value optimized out>, line=50, function=0x7ffff7bb7130 "void boost::mutex::lock()") at assert.c:81
#3 0x00007ffff7b930f3 in boost::mutex::lock (this=0x7fffe2c1b0b8) at /usr/include/boost/thread/pthread/mutex.hpp:50
#4 0x00007ffff7b9596c in boost::unique_lock<boost::mutex>::lock (this=0x7fffe48b3b40) at /usr/include/boost/thread/locks.hpp:349
#5 0x00007ffff7b958db in boost::unique_lock<boost::mutex>::unique_lock (this=0x7fffe48b3b40, m_=...) at /usr/include/boost/thread/locks.hpp:227
#6 0x00007ffff6ac2bb7 in Vi::Logger::ThreadedQueue (this=0x7fffe2c1ade0) at /data/repos_ViNotion/stdcomp/Logging/trunk/src/Logger.cpp:198
#7 0x00007ffff6acf2b2 in boost::_mfi::mf0<void, Vi::Logger>::operator() (this=0x7fffe2c1d890, p=0x7fffe2c1ade0) at /usr/include/boost/bind/mem_fn_template.hpp:49
#8 0x00007ffff6acf222 in boost::_bi::list1<boost::_bi::value<Vi::Logger*> >::operator()<boost::_mfi::mf0<void, Vi::Logger>, boost::_bi::list0> (this=0x7fffe2c1d8a0, f=..., a=...) at /usr/include/boost/bind/bind.hpp:253
#9 0x00007ffff6acf1bd in boost::_bi::bind_t<void, boost::_mfi::mf0<void, Vi::Logger>, boost::_bi::list1<boost::_bi::value<Vi::Logger*> > >::operator() (this=0x7fffe2c1d890) at /usr/include/boost/bind/bind_template.hpp:20
#10 0x00007ffff6aceff2 in boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf0<void, Vi::Logger>, boost::_bi::list1<boost::_bi::value<Vi::Logger*> > > >::run (this=0x7fffe2c1d760)
at /usr/include/boost/thread/detail/thread.hpp:56
#11 0x00007ffff2cc5230 in thread_proxy () from /usr/lib/libboost_thread.so.1.42.0
#12 0x00007ffff4d87971 in start_thread (arg=<value optimized out>) at pthread_create.c:304
#13 0x00007ffff549c92d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112
#14 0x0000000000000000 in ?? ()
Возможно ли, что mMutex не разблокируется в сочетании с использованием unique_lock () и последующим прерыванием потока?