带有boost :: condition_variable的死锁

时间:2016-11-30 10:46:30

标签: c++ multithreading boost condition-variable

我对这个问题感到有些困惑,所以这是我的求救之地。

我有一个管理器将一些事件推送到队列,该队列在另一个线程中继续。 我不希望这个线程“忙着等待”队列中的事件,因为它可能一直是空的(并且它可能总是满的)。 我还需要m_bShutdownFlag在需要时停止线程。 所以我想在这种情况下尝试condition_variable:如果某些东西被推送到队列,那么线程就会开始工作。

简化代码:

class SomeManager {
public:
    SomeManager::SomeManager()
        : m_bShutdownFlag(false) {}

    void SomeManager::Initialize() {
        boost::recursive_mutex::scoped_lock lock(m_mtxThread);
        boost::thread thread(&SomeManager::ThreadProc, this);
        m_thread.swap(thread);
    }

    void SomeManager::Shutdown() {
        boost::recursive_mutex::scoped_lock lock(m_mtxThread);
        if (m_thread.get_id() != boost::thread::id()) {
            boost::lock_guard<boost::mutex> lockEvents(m_mtxEvents);
            m_bShutdownFlag = true;
            m_condEvents.notify_one();
            m_queue.clear();
        }
    }

    void SomeManager::QueueEvent(const SomeEvent& event) {
        boost::lock_guard<boost::mutex> lockEvents(m_mtxEvents);
        m_queue.push_back(event);
        m_condEvents.notify_one();
    }

private:
    void SomeManager::ThreadProc(SomeManager* pMgr) {
        while (true) {
            boost::unique_lock<boost::mutex> lockEvents(pMgr->m_mtxEvents);
            while (!(pMgr->m_bShutdownFlag || pMgr->m_queue.empty()))
                pMgr->m_condEvents.wait(lockEvents);

            if (pMgr->m_bShutdownFlag)
                break;
            else
                /* Thread-safe processing of all the events in m_queue */
        }
    }

    boost::thread m_thread;
    boost::recursive_mutex m_mtxThread;
    bool m_bShutdownFlag;

    boost::mutex m_mtxEvents;
    boost::condition_variable m_condEvents;
    SomeThreadSafeQueue m_queue;
}

但是当我通过两次(或多次)几乎同时调用QueueEvent来测试它时,它会永远锁定在boost::lock_guard<boost::mutex> lockEvents(m_mtxEvents);行。

似乎第一个电话不会释放lockEvents,所以其余的只是等待它的释放。

请帮助我找出我做错了什么,以及如何解决这个问题。

2 个答案:

答案 0 :(得分:0)

在ThreadProc内部,而(ture)循环,lockEvents在任何情况下都不会被解锁。尝试放置锁并在范围内等待。

答案 1 :(得分:0)

您的代码需指出一些事项:

  1. 您可能希望在调用shutdown后加入您的主题,以确保您的主线程在其他主题之前没有完成。
  2. m_queue.clear();关闭是在m_mtxEvents互斥锁之外完成的,这意味着它不像您认为的那样是线程安全的。
  3. 您的线程安全处理&#39;队列应该只是关闭一个项目然后在你去处理事件时释放锁定。您没有明确显示,但如果不这样做,将导致锁定无法添加项目。
  4. 关于这样的线程阻塞的好消息是,你可以轻松地打破并检查其他线程正在做什么,并找到持有锁的那个。根据我的评论#3,你可能需要很长时间来处理一个事件。另一方面,可能是你已经死锁了。在任何情况下,您需要的是使用您的调试器准确确定您做错了什么,因为您的样本没有足够的证明您的问题。