32
votes

In my application, I have an int and a bool variable, which are accessed (multiple write/read) by multiple threads. Currently, I am using two mutexes, one for int and one for bool to protect those variables.

I heard about using atomic variables and operators to write lock-free multi-thread program. My questions are

  1. What's the definition of atomic variables and operators?
  2. What's the main difference between std::atomic and boost/atomic.hpp? Which one is more standard or popular?
  3. Are these libraries platform-dependent? I am using gnu gcc 4.6 on Linux at the moment, but ideally it shall be cross-platform. I heard that the definition of "atomic" actually depends on the hardware as well. Can anyone explain that as well?
  4. What's the best way to share a bool variable among multiple threads? I would prefer not to use the "volatile" keyword.

Are these code thread-safe?

double double_m; // double_m is only accessed by current thread.
std::atomic<bool> atomic_bool_x;
atomic_bool_x = true && (double_m > 12.5);

int int_n; // int_n is only accessed by current thread.
std::atomic<int> atomic_int_x;
std::atomic<int> atomic_int_y;
atomic_int_y = atomic_int_x * int_n;
4
That's a lot of questions to be asking all at once. Also, are you asking if the C++ standard library is... standard? And platform-dependent?Nicol Bolas

4 Answers

18
votes

I'm not an expert or anything, but here's what I know:

  1. std::atomic simply says that calling load and store (and a few other operations) concurrently is well-defined. An atomic operation is indivisible - nothing can happen 'in-between'.
  2. I assume std::atomic is based off of boost::atomic. If you can, use std, otherwise use boost.
  3. They are both portable, with the std being completely so, however your compiler will need to support C++11
  4. Likely std::atomic_bool. You should not need to use volatile.

Also, I believe load/store differs from operator=/operator T only load/store are atomic.

Nevermind. I checked the standard and it appears that the operators are defined in terms of load/store/etc, however they may return different things.

Further reading:

7
votes

Volatile is orthogonal to what you use to implement atomics. In C++ it tells the compiler that certain it is not safe to perform optimizations with that variable. Herb Sutters lays it out:

To safely write lock-free code that communicates between threads without using locks, prefer to use ordered atomic variables: Java/.NET volatile, C++0x atomic, and C-compatible atomic_T.

To safely communicate with special hardware or other memory that has unusual semantics, use unoptimizable variables: ISO C/C++ volatile. Remember that reads and writes of these variables are not necessarily atomic, however.

Finally, to express a variable that both has unusual semantics and has any or all of the atomicity and/or ordering guarantees needed for lock-free coding, only the ISO C++0x draft Standard provides a direct way to spell it: volatile atomic.

(from http://drdobbs.com/article/print?articleId=212701484&siteSectionName=parallel)

2
votes
  1. See std::atomic class template
  2. std::atomic is standard since C++11, and the Boost stuff is older. But since it is standard now, I would prefer std::atomic.
  3. ?? You can use std::atomic with each C++11 compiler on each platform you want.
  4. Without any further information...

    std::atomic;

1
votes

I believe std::atomic (C++11) and boost.atomic are equivalent. If std::atomic is not supported by your compiler yet, use boost::atomic.