使用 front() + pop() 的线程安全队列

Thread safe queue with front() + pop()

我已经创建了一个线程安全队列(见代码)。 class 似乎有效,但现在我想使组合 front() 和 pop() 线程安全,线程首先获取元素,然后确定删除相同的元素。我可以想出一些解决方案,但它们对用户端来说并不优雅,否则将失去强大的异常安全保证。

第一个解决方案是用户只需锁定 ThreadQueueu,而不是调用 front() 和 pop() 并解锁 ThreadQueue。然而,class 的整个想法是用户不必担心线程安全。

第二种解决方案是在重载函数front() 中锁定队列,只在pop() 中解锁。但是,在这种情况下,不允许用户只调用front() 或pop(),不友好..

我想到的第三个选项是在 class (frontPop) 中创建一个 public 函数,returns 前面的元素并将其删除。但是在这种情况下,异常安全性消失了。

有什么既对用户友好(优雅)又能保持异常安全的解决方案?

class ThreadQueue: private std::queue<std::string>
{
  mutable std::mutex d_mutex;

  public:
    void pop()
    {
      lock_guard<mutex> lock(d_mutex);
      pop();
    }

    std::string &front()
    {
      lock_guard<mutex> lock(d_mutex);
      return front();
    }

    // All other functions

  private:

};

通常的解决方案是提供一个组合的 front & pop,它接受一个引用来存储弹出的值,并且 returns 一个 booltrue 如果一个值弹出:

bool pop(std::string& t) {
  lock_guard<mutex> lock(d_mutex);

  if (std::queue<std::string>::empty()) {
    return false;
  }

  t = std::move(std::queue<std::string>::front());
  std::queue<std::string>::pop();
  return true;
}

移动赋值引发的任何异常都发生在队列被修改之前,维护了值类型的移动赋值运算符提供的异常保证。