Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread-safe C++ stack

I'm new to C++ and am writing a multi-threaded app whereby different writers will be pushing objects onto a stack and readers pulling them off the stack (or at least pushing the pointer to an object)..

Are there any structures built-into C++ which can handle this without adding locking code etc.? If not, what about the Boost libraries?

EDIT:

Hi. Thanks for the initial great answers. I guess one reason I thought this could be built-in was that I was thinking purely in x86 space and thought that a PUSH/POP of pointers should be an atomic action at the instruction level.

I'm not sure if my initial hunch is true or not, but I guess this would not necessarily be true across all platforms. Though if running on x86, do you get atomic PUSHes and POPs to the stack and if so, does this essentially make it lock-free?

like image 631
bugmenot77 Avatar asked Apr 26 '09 09:04

bugmenot77


People also ask

Is stack thread-safe C++?

4.1.Although the Java Stack is thread-safe and straight-forward to use, there are major disadvantages with this class: It doesn't have support for setting the initial capacity. It uses locks for all the operations. This might hurt the performance for single threaded executions.

What is thread-safe in C?

Thread safety A threadsafe function protects shared resources from concurrent access by locks. Thread safety concerns only the implementation of a function and does not affect its external interface. The use of global data is thread-unsafe.

Is ArrayDeque thread-safe?

Class ArrayDeque<E> Resizable-array implementation of the Deque interface. Array deques have no capacity restrictions; they grow as necessary to support usage. They are not thread-safe; in the absence of external synchronization, they do not support concurrent access by multiple threads.

Is Strncpy thread-safe?

strcpy() and strdup() are not thread safe, they are thread agnostic. The only memory locations accessed by those functions are their own local variables, and locations to which your program provides pointers.


1 Answers

Yep: Boost.Thread is great, and should fit your needs very well. (These days, many people say that you could almost count Boost as built-in functionality.)

There is still no class that you could use out-of-the-box, but once you have the synchronization primitives at hand, it really is quite simple to implement your own thread-safe wrapper around, for example, std::stack. It could look something like this (not implementing every method...):

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

If you are new to C++, please learn about RAII. Relevant to this case, Boost.Thread has the "scoped lock" classes to make it difficult to shoot yourself in the leg by forgetting to release a lock.

If you ever find yourself writing code like this:

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

, then you should just say no, and go RAII instead (syntax not directly from Boost):

void doStuff() {
  scoped_lock lock;
  if (!condition) {
    reportError();
    return;
  }
  doStuffThatMayThrow();
  doMoreStuff();
}

The point is that when the scoped_lock object goes out of scope, its destructor releases the resource -- in this case, the lock. This will always happen, no matter whether you exit the scope by throwing an exception, or by executing the odd return statement that your colleague sneakily added in the middle of your function, or simply by reaching the end of the function.

like image 194
Reunanen Avatar answered Oct 26 '22 23:10

Reunanen