std::lock_guard vs std::unique_lock vs std::scoped_lock
If you’ve ever written concurrent code in C++ or any other language, then you know how difficult it can be to properly protect access to resources without causing data races or deadlocks. C++11 and C++17 have introduced several great locking mechanisms to help programmers write concurrent code, but which one(s) should you use in your own code?
Back to basics: What is a lock?
A lock is a synchronization mechanism that enforces mutual exclusion of threads. In other words, a lock ensures that only one thread can access a shared resource at a time.
To access a shared resource protected by a lock, a thread must acquire (take ownership of) the lock. If the lock is held by another thread, then the new thread will be blocked (put in a waiting state). Once the other thread releases the lock, then the new thread can access the resource by acquiring the lock for itself.
Why is this needed? Imagine if Thread A is reading data from MyData. Now imagine that at the same exact time, Thread B makes a change to MyData. What would you expect Thread A to read? Would it read the original data from MyData before Thread B’s changes, or after? The code where the read happens is called the critical section, and it must be protected through mutual exclusion.