c++ - 在释放互斥锁之前或之后通知消费者线程?

标签 c++ multithreading c++11 mutex

下面是 C++ concurrency in action 一书中的 list 4.5,它使用条件变量定义了线程安全队列。

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

template<typename T>
class threadsafe_queue
{
private:
    mutable std::mutex mut;
    std::queue<T> data_queue;
    std::condition_variable data_cond;
public:
    threadsafe_queue()
    {}
    threadsafe_queue(threadsafe_queue const& other)
    {
        std::lock_guard<std::mutex> lk(other.mut);
        data_queue=other.data_queue;
    }

    void push(T new_value)
    {
        std::lock_guard<std::mutex> lk(mut);
        data_queue.push(new_value);
        data_cond.notify_one();
    }

    void wait_and_pop(T& value)
    {
        std::unique_lock<std::mutex> lk(mut);
        data_cond.wait(lk,[this]{return !data_queue.empty();});
        value=data_queue.front();
        data_queue.pop();
    }

std::shared_ptr<T> wait_and_pop()
{
    std::unique_lock<std::mutex> lk(mut);
    data_cond.wait(lk,[this]{return !data_queue.empty();});
    std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
    data_queue.pop();
    return res;
}

bool try_pop(T& value)
{
    std::lock_guard<std::mutex> lk(mut);
    if(data_queue.empty)
        return false;
    value=data_queue.front();
    data_queue.pop();
}

std::shared_ptr<T> try_pop()
{
    std::lock_guard<std::mutex> lk(mut);
    if(data_queue.empty())
        return std::shared_ptr<T>();
    std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
    data_queue.pop();
    return res;
}

bool empty() const
{
    std::lock_guard<std::mutex> lk(mut);
    return data_queue.empty();
}
};

int main()
{}

在 push 函数中,另一个线程在 mutex 仍然被锁定时被通知。 mutex 释放后立即通知 popper 线程不是更好吗?例如,像这样:

void push(T new_value)
{
    {
        std::lock_guard<std::mutex> lk(mut)
        data_queue.push(new_value);
    }
    data_cond.notify_one();
}

我知道它们在功能上做同样的事情。我在想在原来的情况下,消费者线程会收到一个错误的通知,最终让它尝试不止一次锁定互斥体。然而,在第二种情况下,我们避免提前唤醒消费者线程,因此,尝试锁定互斥量可以在第一时间成功。

最佳答案

没关系,最终的结果是一样的。如果您先通知而不是解锁互斥锁,监听线程将收到通知,但仍会锁定在互斥锁上,一旦互斥锁解锁,线程将继续执行。

如果您首先解锁互斥量,则线程在收到通知之前不会知道条件已准备就绪,并且会等待条件变量(禁止虚假唤醒)。

最后,监听线程只有在两个条件都满足后才会继续执行 - 互斥锁被解锁,变量被通知。

关于c++ - 在释放互斥锁之前或之后通知消费者线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34620473/

相关文章:

c++ - 不允许的系统调用 : SYS_socketcall - Error when trying to verify ISBN

c++ - 与 C++ 相关的文件

c++ - 在 Visual Studio 2010 编译选项中启用 C++ 异常

c - “post”在sem_post中代表什么?

c# - 委托(delegate)和跨线程异常

java - 定时器内存泄漏

c++ - 在 openCV 中查看 8 位 RAW 图像文件

c++ - 如何在 gdb 中打印 `std::array` 内容?

c++ - Visual Studio 2010 和 std::function

c++ - 由于模数运算符导致的编译代码问题