c++ - condition_variable,引用和线程:谁拥有锁?

标签 c++ c++11 concurrency condition-variable

假设我有一个包含std::queue的ThreadQueue类,并且我将每个std::ref的实例传递给线程。进一步假设,线程1(主线程)创建并保存ThreadQueue对象,并将消息倒入其中,第二个线程的任务是将这些消息传入时将其放入并放置在某个地方,例如,将其写入日志文件。

该类如下所示:

#include <queue>
#include <mutex>
#include <condition_variable>

using namespace std;

template <typename T>
class ThreadQueue
{
    queue<T> q_;
    mutex mtx;
    unique_lock<mutex> lck;
    condition_variable cv;

public:
    ThreadQueue() { lck = unique_lock<mutex>(mtx); }
    ~ThreadQueue() { if (lck.owns_lock()) lck.unlock(); }

    void enqueue (const T&);
    T dequeue ();
};

template <typename T>
void ThreadQueue<T>::enqueue (const T& t)
{
    lck.lock();
    q_.push(t);
    lck.unlock();
    cv.notify_one();
}

template <typename T>
T ThreadQueue<T>::dequeue ()
{
    cv.wait(lck);
    lck.lock();
    T t = q_.front(); // let's assume that's a copy assignment, because
    q_.pop();         // pop() calls the descructor.
    lck.unlock();
    return t;
}

然后主要是:
ThreadQueue<std::pair<int, std::string>> logs;
// and maybe something like:
std::thread logger(std::ref(logs));

关键行是cv.wait(lck);文档明确指出lck必须是unique_lock对象,其互斥对象当前已被此线程锁定。

现在的问题是:谁真正锁定互斥锁,谁拥有锁,线程1或线程2?

最佳答案

代码中有两个主要错误:

  • unique_lock不应是成员变量。它必须在堆栈上创建,以便在保留作用域(正常返回或发生异常)时自动为您释放锁定。
  • 只有在您检查队列确实为空之后,才必须调用
  • cv.waitstd::condition_variable是一种无状态的通信机制,如果在没有服务员的情况下发出信号,则信号会丢失。也有虚假的唤醒。您可能想使用cv.wait([this] { return !q_.empty(); });为您正确处理条件变量的等待。

  • 例如。:
    using namespace std;
    
    template <typename T>
    class ThreadQueue
    {
        queue<T> q_;
        mutex mtx;
        condition_variable cv;
    
    public:
        void enqueue (const T&);
        T dequeue ();
    };
    
    template <typename T>
    void ThreadQueue<T>::enqueue (const T& t)
    {
        {
            lock_guard<mutex> lck(mtx);
            q_.push(t);
        }
        cv.notify_one(); // Optimization: release the lock before signalling.
    }
    
    template <typename T>
    T ThreadQueue<T>::dequeue ()
    {
        unique_lock<mutex> lck(mtx);
        cv.wait(lck, [this] { return !q_.empty(); });
        T t = q_.front();
        q_.pop();
        return t;
    }
    

    Who owns the lock?



    锁定互斥锁的线程拥有该锁,或者进入了关键部分。这里的std::lock_guardstd::unique_lock都将互斥锁锁定在构造函数中,并在析构函数中解锁(在正常范围退出或异常时)。

    关于c++ - condition_variable,引用和线程:谁拥有锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60156002/

    相关文章:

    c++ - 将英特尔的 MKL(BLAS 和 LAPACK)链接到 GCC

    c++ - 如何使此模板 typedef 在 C++11 中有效?

    c++ - C++中调用类模板的函数模板

    c++ - 使用一元调整大小减小非默认可构造元素的容器大小

    python - 有效整合concurrent.futures并行执行的结果?

    c++ - 警告 : state has already been added to QState

    c++ - g++ -Wreorder 的意义何在?

    c++ - std::initializer_list 会导致生命周期问题吗?

    java - Java中并发Cache的修改

    concurrency - F# 并发的不同方法之间的关系是什么