【问题标题】:Lock an rvalue argument for thread safe queue's move constructor?为线程安全队列的移动构造函数锁定右值参数?
【发布时间】:2014-11-21 23:06:45
【问题描述】:

在阅读c++ concurrency in action这本书时,我正在尝试编写一个线程安全队列。

代码:

template<typename T>
class ThreadsafeQueue
{
public:
    using Guard = std::lock_guard<std::mutex>;

    //! default Ctor
    ThreadsafeQueue() = default;

    //! copy Ctor
    ThreadsafeQueue(ThreadsafeQueue const& other)
    {
        Guard g{other.mutex_};
        q_ = other.q_;
    }

    //! move Ctor <----my question
    ThreadsafeQueue(ThreadsafeQueue && other)noexcept
    {
        q_ = std::move(other.q_);
    }

    //! other members...

private:
    std::queue<T> q_;
    std::mutex mutex_;
    std::condition_variable cond_;
};

我的问题是我是否应该在移动构造函数中锁定参数的other.mutex_?为什么?

【问题讨论】:

    标签: c++ multithreading c++11 thread-safety move-semantics


    【解决方案1】:

    移动值是一种变异操作。

    变异需要独占访问才能避免数据竞争。

    因此调用者应该已经持有锁。将对象作为右值传递的调用者知道它将被改变(或者至少承诺接收函数可以这样做)。

    现实:这一切都不太可能发生。由于您要移动整个队列,因此您可能处于应用程序的某个位置,该位置仍然(逻辑上)单线程 w.r.t 队列。

    只有在可以并发访问之后才需要锁定。


    这也有点像 catch-22:如何锁定要移动的互斥锁?

    【讨论】:

    • 我的两分钱是你应该继续以技术上安全的方式(或至少默认为安全方式),因为它不太可能发生:它很可能不会发生在代码的关键部分,所以它应该伤害任何“正确”的事情。
    【解决方案2】:

    取决于您如何定义 ThreadsafeQueue 的移出状态。我看到了两种合理的常见方式:

    • 移出队列为空,可以将新项目推入其中等等。那么你的问题的答案是肯定的。在大多数情况下,我个人更喜欢这个。
    • 移出队列处于未指定状态,只能被破坏或分配给它。那么答案是否定的。用户有责任不要从可以在其他地方使用的队列中移动(关于析构函数的想法相同)。

    【讨论】:

    • 有趣的是,可以在其他地方使用的 X 中的“不(做 X)的责任通常由...互斥来处理.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-10
    • 1970-01-01
    • 2015-06-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多