Context:
I know that std::lock_guard
became kind of deprecated since the arrival of c++17 with std::scoped_lock
.
I also know that std::scoped_lock
is preferred since it can handle several mutexes and uses a deadlock avoidance algorithm the same way as std::lock
does.
I'm interested here in the case we have only one single mutex and thus we don't need to care about deadlock avoidance.
I have read from this answer that:
You can consider
std::lock_guard
deprecated. The single argument case ofstd::scoped_lock
can be implemented as a specialization and such you don't have to fear about possible performance issues.
Question:
I'm wondering how much this sentence is true.
I mean, is it guaranteed (by the standard) that with a single mutex, std::scoped_lock
will be specialized so that it will get rid of any unnecessary overhead due to deadlock avoidance handling ?
My thoughts:
After some investigation on the question, I found from cppreference the following sentence:
If several mutexes are given, deadlock avoidance algorithm is used as if by
std::lock
.
Which could let us deduce that such a thing would not happen otherwise (i.e. if only one mutex is given).
But once again, it is just an assumption.
From this c++ draft I don't see any explicit mention about such a specialization.
The only sentence I got is:
When
sizeof...(MutexTypes)
is1
, the suppliedMutex
type shall meet the Cpp17BasicLockable requirements. Otherwise, each of the mutex types shall meet the Cpp17Lockable requirements.
(emphasis mine)
I know that the BasicLockable requirements mandate the existence of lock()
and unlock()
functions which meet the conditions such as defined here.
On the other hand, the Lockable requirements assume the BasicLockable requirements with the addition of a try_lock()
function which meet the conditions such as defined there.
I know that the try_lock()
function is required in order to run the deadlock avoidance algorithm used by std::lock
.
From what's stated in the above c++ draft extract, the try_lock()
function is thus not required if we give only one mutex to std::scoped_lock
.
Is this sufficient to deduce/consider that the above specialization is always defined (and presumably behaves as std::lock_guard
would do).
I would say yes but as I never saw any explicit mention about it, I wonder if I'm right or if I missed something ?
EDIT:
I just noticed that I missed the most important part here which states:
Effects: Initializes
pm
withtie(m...)
. Then ifsizeof...(MutexTypes)
is0
, no effects. Otherwise ifsizeof...(MutexTypes)
is1
, thenm.lock()
. Otherwise,lock(m...)
.
(emphasis mine)
Which answers my interrogations, std::lock
is called only when there is more than one given mutex. I should have seen it before asking the question...
If you read the specification of lock_guard
(which is right above scoped_lock
) it should be clear.
Initializes pm with m. Calls m.lock()
Initializes pm with tie(m...). [...] Otherwise if sizeof...(MutexTypes) is 1, then m.lock(). [...]
It doesn't explicitly mention to use lock_guard
but it is required to have the same behavior.