In the previous parts of this serie, we saw some C++11 Synchronization techniques: locks, lock guards and atomic references.
In this small post, I will present the results of a little benchmark I did run to compare the different techniques. In this benchmark, the critical section is a single increment to an integer. The critical section is protected using three techniques:
- A single std::mutex with calls to lock() and unlock()
- A single std::mutex locked with std::lock_guard
- An atomic reference on the integer
The tests have been made with 1, 2, 4, 8, 16, 32, 64 and 128 threads. Each test is repeated 5 times.
The results are presented in the following figure:
As expected, the mutex versions are much slower than the atomic one. An interesting point is that the the atomic version has not a very good scalability. I would have expected that the impact of adding one thread would not be that high.
I'm also surprised that the lock guard version has a non-negligible overhead when there are few threads.
In conclusion, do not locks when all you need is modifying integral types. For that, std::atomic is much faster. Good Lock-Free algorithms are almost always faster than the algorithms with lock.
The sources of the benchmark are available on Github: https://github.com/wichtounet/articles/tree/master/src/threads/benchmark