不同线程间的互斥锁同步

mutex lock synchronization between different threads

由于我最近开始编写多线程程序,所以这可能是一个愚蠢的问题。我发现了很棒的互斥锁和条件变量用法。据我所知,用途是:

  1. 保护 code/shared 部分资源不被多线程访问破坏。因此锁定该部分,从而可以控制将访问哪个线程。
  2. 如果一个线程正在等待来自另一个线程的 resource/condition,可以使用 cond.wait() 而不是每毫秒轮询一次

现在考虑以下 class 示例:

class Queue {
private:
    std::queue<std::string> m_queue; 
    boost::mutex m_mutex; 
    boost::condition_variable m_cond; 
    bool m_exit;

public:
    Queue()
    : m_queue() 
    , m_mutex() 
    , m_cond()
    , m_exit(false) 
    {}

    void Enqueue(const std::string& Req) 
    { 
        boost::mutex::scoped_lock lock(m_mutex);
        m_queue.push(Req);
        m_cond.notify_all();
    }

    std::string Dequeue() 
    { 
        boost::mutex::scoped_lock lock(m_mutex);
        while(m_queue.empty() && !m_exit) 
        {      
            m_cond.wait(lock);     
        }

        if (m_queue.empty() && m_exit) return "";

        std::string val = m_queue.front(); 
        m_queue.pop(); 
        return val; 
    }

    void Exit()
    {
        boost::mutex::scoped_lock lock(m_mutex);
        m_exit = true;
        m_cond.notify_all();
    }
} 

在上面的示例中,可以调用 Exit(),它会通知等待 Dequeue 的线程是时候退出了,而无需等待队列中的更多数据。 我的问题是既然Dequeue已经获得了锁(m_mutex),那么Exit如何获得同样的锁(m_mutex)呢?是不是除非Dequeue释放锁,否则只有Exit才能拿到锁?

我在析构函数实现中也看到过这种模式,使用相同的 class 成员互斥锁,析构函数通知所有线程(class 方法)是时候终止它们各自的 loops/functions等等

正如 Jarod 在评论中提到的,电话

m_cond.wait(lock)

保证以原子方式解锁互斥锁,为线程释放它,并开始监听条件变量的通知(参见 here)。 这种原子性还确保在设置监听后线程中的任何代码都被执行(因此不会错过任何通知调用)。这当然假设线程首先锁定互斥量,否则所有赌注都关闭。

另一个需要理解的重要一点是条件变量可能会受到“spurious wakeups”的影响,因此拥有第二个布尔条件很重要(例如,在这里,您可以检查队列是否为空)以便您不会以空队列醒来。像这样:

m_cond.wait(lock, [this]() { return !m_queue.empty() || m_exit; });