Multithreading 使用多线程和互斥体时对互斥体的断言

Multithreading 使用多线程和互斥体时对互斥体的断言,multithreading,boost,mutex,Multithreading,Boost,Mutex,作为项目的一部分,我正在编写一个记录器函数。当程序想要记录某些内容时,此记录器函数会发送一封电子邮件。由于SMTP服务器没有响应,我决定在单独的线程中发送邮件。 此线程从日志函数填充的std::deque读取消息。 线程的设置如下所示: while (!boost::this_thread::interruption_requested()) { EmailItem emailItem; { boost::unique_lock<boost::mutex> lock(

作为项目的一部分,我正在编写一个记录器函数。当程序想要记录某些内容时,此记录器函数会发送一封电子邮件。由于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));
          }
      }
  }
}
{
  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;
}