【问题标题】:Thread safe queue implementation : Efficient implementation of pop()线程安全队列实现:pop() 的高效实现
【发布时间】:2020-11-23 12:43:46
【问题描述】:

我正在尝试实现队列的线程安全版本,并在实现 pop() 的包装器时遇到问题。参考下面的代码。由于限制,无法粘贴整个代码。

bool internal_pop_front_no_lock(T& item)
{
    bool isDataAvailable = false;

    if (!m_Queue.empty())
    {
        item = m_Queue.front();
        m_Queue.pop();
        isDataAvailable = true;
    }

   return isDataAvailable;
}

现在我觉得item = m_Queue.front(); 行会复制数据。有没有办法避免复制?还是我误会了什么?

【问题讨论】:

  • m_Queue 是 std::queue 吗?
  • @Surt 这是您将 OP 指向 minimal reproducible example 的位置。
  • @surt .. 是的 m_Queue 是 std::queue。

标签: c++ c++11 queue


【解决方案1】:

只有一种方法可以避免复制,如果你移动这个对象然后返回它。因为即使你可以在不复制的情况下访问m_Queue.front(),一旦你这样做m_Queue.pop();,这个对象就会被销毁,如果你需要在这个点之外访问这个对象,你需要复制或移动这个对象。所以像这样的事情是你唯一的机会:

std::optional<T> internal_pop_front_no_lock()
{
    std::optional<T> result;

    if (!m_Queue.empty())
    {
        result = std::move(m_Queue.front());
        m_Queue.pop();
    }

   return result;
}

【讨论】:

    【解决方案2】:

    由于std::queue 存储实际值,您能做的最好的事情就是将值移出(如std::move)。对于许多复杂的对象,即使复制很昂贵,移动也很便宜。

    如果您有一个复杂的对象,移动成本很高,您可以有一个unique_ptrs 的队列;这些移动起来很便宜(而且不可能复制)。

    使用std::unique_ptr&lt;int&gt; 或其他东西测试您的线程安全队列,并确保它有效。然后你就会知道你的队列没有复制操作。然后由您队列中的用户(可能是您自己)来确保他们放入队列中的物品足够便宜以便移动。

    boost::optional&lt;T&gt;std::optional&lt;T&gt; 在这里非常有用,因为您有一个 T&amp; 和一个 bool 来指示它是否已填充。但核心是:

    result = std::move(m_Queue.front()); // move
    

    而不是

    result = m_Queue.front(); // copy
    

    当你提取值时。

    ...

    我自己,我对这种方法持怀疑态度。它的长名称是一个危险信号,它所做的只是包装了几个std::queue 方法。与直接调用 std::queue 方法相比,它看起来并没有降低复杂性。

    根据我的经验,线程安全队列的棘手部分是决定通知的工作方式、中止、批处理操作(pop_many、push_many)等。相比之下,与queue 的底层交互非常简单。

    【讨论】:

      猜你喜欢
      • 2012-05-30
      • 1970-01-01
      • 2017-06-14
      • 2010-10-22
      • 1970-01-01
      • 2013-07-24
      • 2010-12-10
      • 2012-11-20
      • 1970-01-01
      相关资源
      最近更新 更多