C++17 introduced a new lock class called std::scoped_lock
.
Judging from the documentation it looks similar to the already existing std::lock_guard
class.
What's the difference and when should I use it?
Late answer, and mostly in response to:
You can consider
std::lock_guard
deprecated.
For the common case that one needs to lock exactly one mutex, std::lock_guard
has an API that is a little safer to use than scoped_lock
.
For example:
{
std::scoped_lock lock; // protect this block
...
}
The above snippet is likely an accidental run-time error because it compiles and then does absolutely nothing. The coder probably meant:
{
std::scoped_lock lock{mut}; // protect this block
...
}
Now it locks/unlocks mut
.
If lock_guard
was used in the two examples above instead, the first example is a compile-time error instead of a run-time error, and the second example has identical functionality as the version which uses scoped_lock
.
So my advice is to use the simplest tool for the job:
lock_guard
if you need to lock exactly 1 mutex for an entire scope.
scoped_lock
if you need to lock a number of mutexes that is not exactly 1.
unique_lock
if you need to unlock within the scope of the block (which includes use with a condition_variable
).
This advice does not imply that scoped_lock
should be redesigned to not accept 0 mutexes. There exist valid use cases where it is desirable for scoped_lock
to accept variadic template parameter packs which may be empty. And the empty case should not lock anything.
And that's why lock_guard
isn't deprecated. scoped_lock
and unique_lock
may be a superset of functionality of lock_guard
, but that fact is a double-edged sword. Sometimes it is just as important what a type won't do (default construct in this case).