Multithreading 使用多线程和互斥体时对互斥体的断言
作为项目的一部分,我正在编写一个记录器函数。当程序想要记录某些内容时,此记录器函数会发送一封电子邮件。由于SMTP服务器没有响应,我决定在单独的线程中发送邮件。 此线程从日志函数填充的std::deque读取消息。 线程的设置如下所示:Multithreading 使用多线程和互斥体时对互斥体的断言,multithreading,boost,mutex,Multithreading,Boost,Mutex,作为项目的一部分,我正在编写一个记录器函数。当程序想要记录某些内容时,此记录器函数会发送一封电子邮件。由于SMTP服务器没有响应,我决定在单独的线程中发送邮件。 此线程从日志函数填充的std::deque读取消息。 线程的设置如下所示: while (!boost::this_thread::interruption_requested()) { EmailItem emailItem; { boost::unique_lock<boost::mutex> lock(
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));
}
}
}
}
{
boost::lock_guard<boost::mutex> lock(mMutex);
mEmailBuffer.push_back(e);
mCond.notify_one();
}
析构函数仅调用线程上的中断,然后将其加入:
mQueueThread.interrupt();
mQueueThread.join();
在主程序中,我使用了多个不同的类,它们也使用了boost线程和互斥,这会导致这种行为吗?不调用logger对象的析构函数不会导致任何错误,使用logger对象不执行任何其他操作也不会导致任何错误
我的猜测是我做了一些非常错误的事情,或者在使用多个线程划分到多个类时线程库中有一个bug。
有人知道这个错误的原因是什么吗
编辑:
我按照@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);
}
}
}
void Vi::Logger::ThreadedQueue()
{
bool bufferOverflow=false;
上次溢出的时间=0;
无符号整数nrOfItems=0;
而(!boost::this_thread::interruption_requested())
{
EmailItem EmailItem;
//检查新的日志条目
{
boost::唯一的锁(mMutex);
while(mEmailBuffer.empty())
等待(锁定);
}
}
}
这个问题仍然存在。然而,问题的回溯向我展示了与初始代码不同的东西:
#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 ?? ()
#0 0x00007ffff53e9ba5在../nptl/sysdeps/unix/sysv/linux/raise.c:64处的raise(sig=)中
#1 0x00007ffff53ed6b0在中止()时处于中止状态。c:92
#2 0x00007FF53E2A71在assert.c:81的uuuu assert_ufail(assertion=0x7FF7BB6407“!pthread_mutex_lock(&m)”,file=,line=50,function=0x7FF7BB7130“void boost::mutex::lock()”)中
#在/usr/include/boost/thread/pthread/mutex.hpp:50处的boost::mutex::lock(this=0x7fffe2c1b0b8)中3 0x00007ff7bf7b930f3
#在/usr/include/boost/thread/locks处的boost::unique_lock::lock(this=0x7fffe48b3b40)中的4 0x00007ffff7b9596c。hpp:349
#在/usr/include/boost/thread/locks处的boost::unique_lock::unique_lock(this=0x7fffe48b3b40,m_=…)中有5个0x00007ffff7b7958db。hpp:227
#6在/data/repos\u ViNotion/stdcomp/Logging/trunk/src/Logger.cpp:198处的Vi::Logger::ThreadedQueue(this=0x7fffe2c1ade0)中的0x00007ff6ac2bb7
#boost::mfi::mf0::operator()(this=0x7fffe2c1d890,p=0x7fffe2c1ade0)中的7 0x00007FF6ACF2B2位于/usr/include/boost/bind/mem_fn_template。hpp:49
#8 0x00007FF6ACF222在/usr/include/boost/bind/bind.hpp:253处的boost::bi::list1::operator()
#9/usr/include/boost/bind/bind_模板中的0x00007ff6acf1bd::bi::bind_t::operator()(this=0x7fffe2c1d890)。hpp:20
#boost::detail::thread_data::run中的10 0x00007ffff6aceff2(this=0x7fffe2c1d760)
at/usr/include/boost/thread/detail/thread.hpp:56
#11/usr/libboost\u thread.so.1.42.0中的线程代理()中的0x00007FF2CC5230
#pthread_create.c:304处的start_线程(arg=)中的12 0x00007ffff4d87971
#位于../sysdeps/unix/sysv/linux/x86_64/clone.S:112的克隆()中的13 0x00007ffff549c92d
#14 0x0000000000000000英寸??()
使用唯一的_lock()然后中断线程可能不会解锁mMutex?在删除互斥锁之前,您应该解锁互斥锁。在退出之前是否加入线程?正如
tyz
所建议的,当互斥体被破坏时,线程仍然可以将其锁定
[编辑]
您没有提供可以编译和运行的完整示例,很难使用它
检查以下与您的示例类似的简单示例:
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <queue>
class Test
{
public:
Test()
{
thread = boost::thread(boost::bind(&Test::thread_func, this));
}
~Test()
{
thread.interrupt();
thread.join();
}
void run()
{
for (size_t i = 0; i != 10000; ++i) {
boost::lock_guard<boost::mutex> lock(mutex);
queue.push(i);
condition_var.notify_one();
}
}
private:
void thread_func()
{
while (!boost::this_thread::interruption_requested())
{
{
boost::unique_lock<boost::mutex> lock(mutex);
while (queue.empty())
condition_var.wait(lock);
queue.pop();
}
}
}
private:
boost::thread thread;
boost::mutex mutex;
boost::condition_variable condition_var;
std::queue<int> queue;
};
int main()
{
Test test;
test.run();
return 0;
}
#包括
#包括
#包括
课堂测试
{
公众:
测试()
{
thread=boost::thread(boost::bind(&Test::thread_func,this));
}
~Test()
{
thread.interrupt();
thread.join();
}
无效运行()
{
对于(尺寸i=0;i!=10000;++i){
boost::lock_guard lock(互斥锁);
排队推送(i);
条件变量通知变量();
}
}
私人:
无效线程_func()
{
而(!boost::this_thread::interruption_requested())
{
{
boost::唯一的锁(互斥锁);
while(queue.empty())
条件变量等待(锁定);
queue.pop();
}
}
}
私人:
boost::线程;
互斥互斥;
boost::条件变量条件变量;
std::队列;
};
int main()
{
试验;
test.run();
返回0;
}
与您的案例进行比较谢谢您的回复。在我的代码中,我只使用作用域锁来锁定互斥锁。因此,它们应该在作用域关闭时自动解锁,不是吗?@Tim,我努力了,但在给定的代码中没有发现任何错误。但是,您得到的错误通常是由于删除了锁定的互斥体而导致的。我在函数末尾显式地添加了互斥体解锁,不幸的是没有成功:mMutex.unlock();mLoggerMutex.unlock();是的,我在退出之前加入线程。另外,据我所知,在线程中锁定互斥锁的地方没有中断点。因此,我不希望线程在中断时仍然锁定互斥体。请再次检查,在连接之前,是否未删除互斥体(正确的互斥体)。两个互斥体都是Logger类的成员变量。此类的析构函数调用线程上的'interrupt()'和'join()'函数。因此,如果我没有说错的话,当线程被连接时,互斥锁应该仍然是活动的。作为最后的手段,试着准备最简单的问题示例,在测试应用程序中使用您的记录器来重现问题。然后删除所有不相关的内容
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <queue>
class Test
{
public:
Test()
{
thread = boost::thread(boost::bind(&Test::thread_func, this));
}
~Test()
{
thread.interrupt();
thread.join();
}
void run()
{
for (size_t i = 0; i != 10000; ++i) {
boost::lock_guard<boost::mutex> lock(mutex);
queue.push(i);
condition_var.notify_one();
}
}
private:
void thread_func()
{
while (!boost::this_thread::interruption_requested())
{
{
boost::unique_lock<boost::mutex> lock(mutex);
while (queue.empty())
condition_var.wait(lock);
queue.pop();
}
}
}
private:
boost::thread thread;
boost::mutex mutex;
boost::condition_variable condition_var;
std::queue<int> queue;
};
int main()
{
Test test;
test.run();
return 0;
}