线程安全的C++堆栈

bug*_*t77 14 c++ stack multithreading boost thread-safety

我是C++的新手,我正在编写一个多线程的应用程序,不同的编写者会将对象推入堆栈,读者将它们从堆栈中拉出(或者至少将指针推到对象上).

是否有内置于C++中的结构可以在不添加锁定代码等的情况下处理此问题?如果没有,Boost库怎么样?

编辑:

你好.感谢最初的好答案.我想我认为这可能是内置的一个原因是我纯粹在x86空间思考并且认为指针的PUSH/POP应该是指令级别的原子动作.

我不确定我最初的预感是否正确,但我想在所有平台上都不一定如此.虽然如果在x86上运行,你是否会将原子PUSH和POP发送到堆栈中,如果是这样,这实际上是否使它无锁?

Reu*_*nen 21

是的:Boost.Thread很棒,应该很好地满足你的需求.(现在,很多人都说你几乎可以将Boost视为内置功能.)

仍然没有可以开箱即用的类,但是一旦掌握了同步原语,例如,实现自己的线程安全包装就非常简单了std::stack.它可能看起来像这样(没有实现每个方法......):

template <typename T> class MyThreadSafeStack {
  public:
    void push(const T& item) {
      boost::mutex::scoped_lock lock(m_mutex);
      m_stack.push(item);
    }
    void pop() {
      boost::mutex::scoped_lock lock(m_mutex);
      m_stack.pop();
    }
    T top() const { // note that we shouldn't return a reference,
                    // because another thread might pop() this
                    // object in the meanwhile
      boost::mutex::scoped_lock lock(m_mutex);
      return m_stack.top();
    }

  private:
    mutable boost::mutex m_mutex;
    std::stack<T> m_stack;
}    
Run Code Online (Sandbox Code Playgroud)

如果您不熟悉 C++,请了解RAII.与此案相关,Boost.Thread具有"范围锁定"类,因为忘记释放锁定而难以在腿部射击.

如果您发现自己编写的代码如下:

void doStuff() {
  myLock.lock();
  if (!condition) {
    reportError();
    myLock.unlock();
    return;
  }
  try {
    doStuffThatMayThrow();
  }
  catch (std::exception& e) {
    myLock.unlock();
    throw e;
  }
  doMoreStuff();
  myLock.unlock();
}
Run Code Online (Sandbox Code Playgroud)

,那么你应该说不,然后去RAII(语法不直接来自Boost):

void doStuff() {
  scoped_lock lock;
  if (!condition) {
    reportError();
    return;
  }
  doStuffThatMayThrow();
  doMoreStuff();
}
Run Code Online (Sandbox Code Playgroud)

关键是当scoped_lock对象超出范围时,它的析构函数会释放资源 - 在本例中是锁定.无论您是通过抛出异常退出范围,还是执行return您的同事偷偷在函数中间添加的奇怪语句,或者只是到达函数末尾,这都会发生.

  • 您应该注意,即使被互斥锁锁定,std容器也不是线程安全的.原因是它们的修改使现有的迭代器无效. (2认同)
  • @ASk - 如果您正在迭代共享的STL容器(或任何共享容器),那么您可能也应该锁定.例如,如果要对容器的内容迭代地执行只读操作,则可以获得读锁定,以便在该操作期间没有人可以通过写入使您的迭代器无效.此外,您需要获取写锁定以对该结构进行更改,以强制等待当前读取(未完成的迭代器)完成. (2认同)

小智 5

当前的 C++ 标准根本没有解决线程问题,因此您的第一个问题的答案是否定的。一般来说,将锁定构建到基本数据结构中是一个坏主意,因为它们没有足够的信息来正确和/或有效地执行它。相反,应该在使用数据结构的类中执行锁定 - 换句话说,在您自己的应用程序类中。