Professional C__ - Marc Gregoire [386]
Instead of using a workaround as described in the previous paragraph, you should try to avoid any possible deadlock situation altogether. If you need to acquire multiple locks, the recommended way is to use the standard std::lock() or std::try_lock() methods described later in the section on mutual exclusion. These methods will obtain or try to obtain a lock on several resources, doing their best to prevent deadlocks.
ATOMIC OPERATIONS LIBRARY
C++11 introduces atomic types on which atomic operations can be applied. These allow atomic accesses, which means that concurrent reading and writing without additional synchronization is allowed. Reads will never result in undefined behavior.
The increment race condition example given in the previous section can be solved by using an atomic type. For example, the following code is not thread-safe and can show race condition behavior as explained earlier:
int counter = 0; // Global variable
...
++counter; // Executed in multiple threads
To make this thread-safe without explicitly using any locks, use an atomic type:
atomic ... ++counter; // Executed in multiple threads You need to include the NAMED ATOMIC TYPE EQUIVALENT ATOMIC TYPE INTEGRAL TYPE atomic_char atomic atomic_schar atomic atomic_uchar atomic atomic_short atomic atomic_ushort atomic atomic_int atomic atomic_uint atomic atomic_long atomic atomic_ulong atomic atomic_llong atomic atomic_ullong atomic atomic_char16_t atomic atomic_char32_t atomic atomic_wchar_t atomic Atomic Type Example This section explains why you should use atomic types. Suppose you have a function called func() that increments an integer given as a reference parameter in a loop: void func(int& counter) { for (int i = 0; i < 10000; ++i) { ++counter; } } Code snippet from atomic\inc_func_non_atomic.cpp Now, you would like to run several threads in parallel, all executing this func() function. By implementing this naively without atomic types, you introduce a race condition. The following main() function launches several threads with the std::thread class defined in the #include #include #include #include int main() { int counter = 0; std::vector for (int i = 0; i < 10; ++i) { threads.push_back(std::thread{func, std::ref(counter)}); } for (auto& t : threads) { t.join(); } std::cout << "Result = " << counter << std::endl; return 0; } Code snippet from atomic\inc_func_non_atomic.cpp Since func() increments the integer 10.000 times, and main() launches 10 background threads, each of which executes func(), the expected result is 100.000. If you execute this program several times, you might get the following output: Result = 86044 Result = 100000 Result = 99726 Result = 90780 Result = 100000 Result = 85054