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



我创建了一个线程安全队列(请参阅代码)。这个类似乎可以工作,但现在我想让front()加pop()的组合线程安全,这样线程首先获取元素,然后确定删除相同的元素。我可以想出一些解决方案,但它们对用户来说并不优雅,否则将失去强大的异常安全保障。

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

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

我想到的第三个选项是在类(frontPop)中创建一个公共函数,该函数返回front元素并将其删除。然而,在这种情况下,异常安全性消失了。

什么是既友好(优雅)又能维护异常安全的解决方案?

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:
};

通常的解决方案是提供一个组合的前端&pop,接受用于存储弹出值的引用,并在弹出值时返回bool,即true

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;
}

移动赋值引发的任何异常都会在修改队列之前发生,从而保持值类型的移动赋值运算符提供的异常保证。

最新更新