【问题标题】:Deadlock with boost::condition_variableboost::condition_variable 的死锁
【发布时间】:2016-11-30 10:46:29
【问题描述】:

我有点被这个问题困住了,所以这是我的求助。

我有一个将一些事件推送到队列的管理器,该队列在另一个线程中进行。 我不希望这个线程“忙于等待”队列中的事件,因为它可能一直是空的(也可能总是满的)。 我还需要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&lt;boost::mutex&gt; lockEvents(m_mtxEvents); 行。

似乎第一个调用永远不会释放lockEvents,所以其余的只是继续等待它的释放。

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

【问题讨论】:

    标签: c++ multithreading boost condition-variable


    【解决方案1】:

    您的代码有几点需要指出:

    1. 您可能希望在调用 shutdown 后加入您的线程,以确保您的主线程不会在其他线程之前完成。
    2. m_queue.clear(); 关机是在你的 m_mtxEvents 互斥锁之外完成的,这意味着它不像你想象的那样线程安全。
    3. 您对队列的“线程安全处理”应该只是取下一个项目,然后在您开始处理事件时释放锁。您没有明确表明这一点,但如果不这样做将导致锁定阻止添加项目。

    关于这样的线程阻塞的好消息是,您可以轻松地中断并检查其他线程正在做什么,并找到持有锁的线程。可能是根据我的评论 #3,您只需要很长时间来处理一个事件。另一方面,您可能遇到了死锁。无论如何,您需要使用调试器准确确定您做错了什么,因为您的示例中没有足够的内容来证明您的问题。

    【讨论】:

    • 谢谢,我已经修复了#1 和#2。我的问题的原因是在队列元素的处理中。由于处理中的while 循环不良,有几个元素会永久处理。
    【解决方案2】:

    在 ThreadProc 的 while(ture) 循环中,lockEvents 在任何情况下都不会被解锁。尝试在作用域内加锁并等待。

    【讨论】:

    • 其实这部分对我来说是最奇怪的。看起来我永远不会处理队列中的任何事件,但事实并非如此。当我两次调用QueueEvent 并在两次调用之间有一些延迟时,一切正常。
    • 无论如何,谢谢你的建议,我会试试的——至少听起来很正常。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多