【问题标题】:C++ queue non lockingC++ 队列非锁定
【发布时间】:2014-12-25 17:24:20
【问题描述】:

我有一个问题,线程 A 从 curl 回调接收视频数据并将数据添加到 std::deque,而线程 B 从 std::deque 读取数据并进行处理。

我在线程 A 向其添加数据时锁定std::deque,并在线程 B 从中读取数据时锁定它。

一切正常,但几分钟后,我的 curl 回调最终停止,不再接收视频数据。
我假设线程 B 处理数据的时间过长,因此持有锁的时间过长,结果 curl 回调最终停止死亡。

是否有任何可以在 C++ 中使用的队列,在添加和读取时我不必锁定它??

如果需要,我可以发布我的代码。

【问题讨论】:

  • 一个简单的方法是将指针推送到双端队列。当您需要处理一个时,只需在弹出指针所需的时间内使用锁。然后在处理数据之前释放锁。 (考虑使用std::unique_ptr,这样您就不必手动管理内存。)
  • 或者让读者有自己的deque,并且只锁定足够长的时间到swap()与共享的空双端队列。交换将比添加或删除项目更快。然后读取器处理其队列副本中的所有内容,清空它,然后再次锁定并与共享的交换它。

标签: c++ c++11 libcurl deque


【解决方案1】:

Boost 提供无锁队列,但它们有限制,例如只允许存储 POD 类型。

一个常见的解决方案是让消费者拥有自己的队列对象,该对象开始为空,并在包含工作时与共享队列对象交换。

std::mutex global_queue_mutex;
std::condition_variable work_available;
std::deque<Work> global_queue;

void consumer()
{
  std::deque<Work> local;
  while (true)
  {
    // wait for work to be available and then swap it into local queue
    {
      std::unique_lock<std::mutex> lock(global_queue_mutex);
      work_available.wait(lock, [&]{ return !global_queue.empty(); });
      local.swap(global_queue);
    }
    for (auto& work : local)
    {
      // do work
    }
    local.clear();
  }
}

void producer()
{
  // ...
  {
    std::lock_guard<std::mutex> lock(global_queue_mutex);
    global_queue.push_back(std::move(work));
  }
  work_available.notify_one();
  // ...
}

消费者只持有足够长的时间来检查工作并进行交换,这将非常快。生产者只持有足够长的时间来将单个项目推入队列。

【讨论】:

    【解决方案2】:

    为避免锁定,您可以使用有界、无锁队列。可以在 boost 中找到这样的东西:boost::spsc_queue

    在生产者端检查一个完整的队列也可以停止卷曲线程以避免过载。

    【讨论】:

      【解决方案3】:

      查看英特尔的线程构建块容器,特别是 concurrent_queueconcurrent_bounded_queue

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-04-22
        • 2017-04-21
        • 1970-01-01
        • 2011-08-30
        • 2017-03-28
        • 2012-02-29
        • 2023-03-17
        相关资源
        最近更新 更多