gcc/libstdc++-v3/include/std
Jonathan Wakely 6cf0040fff libstdc++: Improve std::lock algorithm
The current std::lock algorithm is the one called "persistent" in Howard
Hinnant's https://howardhinnant.github.io/dining_philosophers.html post.
While it tends to perform acceptably fast, it wastes a lot of CPU cycles
by continuously locking and unlocking the uncontended mutexes.
Effectively, it's a spin lock with no back-off.

This replaces it with the one Howard calls "smart and polite". It's
smart, because when a Mi.try_lock() call fails because mutex Mi is
contended, the algorithm reorders the mutexes until Mi is first, then
calls Mi.lock(), to block until Mi is no longer contended.  It's
polite because it uses std::this_thread::yield() between the failed
Mi.try_lock() call and the Mi.lock() call. (In reality it uses
__gthread_yield() directly, because using this_thread::yield() would
require shuffling code around to avoid a circular dependency.)

This version of the algorithm is inspired by some hints from Howard, so
that it has strictly bounded stack usage. As the comment in the code
says:

// This function can recurse up to N levels deep, for N = 1+sizeof...(L1).
// On each recursion the lockables are rotated left one position,
// e.g. depth 0: l0, l1, l2; depth 1: l1, l2, l0; depth 2: l2, l0, l1.
// When a call to l_i.try_lock() fails it recurses/returns to depth=i
// so that l_i is the first argument, and then blocks until l_i is locked.

The 'i' parameter is the desired permuation of the lockables, and the
'depth' parameter is the depth in the call stack of the current
instantiation of the function template. If i == depth then the function
calls l0.lock() and then l1.try_lock()... for each lockable in the
parameter pack l1.  If i > depth then the function rotates the lockables
to the left one place, and calls itself again to go one level deeper.
Finally, if i < depth then the function returns to a shallower depth,
equivalent to a right rotate of the lockables.  When a call to
try_lock() fails, i is set to the index of the contended lockable, so
that the next call to l0.lock() will use the contended lockable as l0.

This commit also replaces the std::try_lock implementation details. The
new code is identical in behaviour, but uses a pair of constrained
function templates. This avoids instantiating a class template, and is a
litle simpler to call where used in std::__detail::__lock_impl and
std::try_lock.

Signed-off-by: Jonathan Wakely <jwakely@redhat.com>

libstdc++-v3/ChangeLog:

	* include/std/mutex (__try_to_lock): Move to __detail namespace.
	(struct __try_lock_impl): Replace with ...
	(__detail::__try_lock_impl<Idx>(tuple<Lockables...>&)): New
	function templates to implement std::try_lock.
	(try_lock): Use new __try_lock_impl.
	(__detail::__lock_impl(int, int&, L0&, L1&...)): New function
	template to implement std::lock.
	(lock): Use __lock_impl.
2021-06-21 18:29:58 +01:00
..
algorithm
any libstdc++: Fix std::any constraints [PR101034] 2021-06-14 15:10:56 +01:00
array
atomic libstdc++: Refactor/cleanup of C++20 atomic wait implementation 2021-04-20 15:14:58 +01:00
barrier [libstdc++] Remove unused hasher instance. 2021-06-08 15:41:31 -07:00
bit libstdc++: Fix <bit> to work freestanding [PR 100060] 2021-04-13 17:54:03 +01:00
bitset libstdc++: Fix doxygen markup for group close commands 2021-04-06 16:43:24 +01:00
charconv libstdc++: Disable floating_to_chars.cc on 16 bit targets 2021-05-20 13:21:41 +01:00
chrono libstdc++: Fix doxygen markup for group close commands 2021-04-06 16:43:24 +01:00
codecvt
complex libstdc++: Fix doxygen markup for group close commands 2021-04-06 16:43:24 +01:00
concepts libstdc++: Implement LWG 3557 change to convertible_to 2021-06-18 11:51:33 -04:00
condition_variable libstdc++: Fix doxygen markup for group close commands 2021-04-06 16:43:24 +01:00
coroutine
deque
execution
filesystem
forward_list
fstream libstdc++: Fix doxygen markup for group close commands 2021-04-06 16:43:24 +01:00
functional
future libstdc++: Fix null dereferences in std::promise 2021-05-04 22:46:24 +01:00
iomanip
ios
iosfwd
iostream libstdc++: Fix doxygen markup for group close commands 2021-04-06 16:43:24 +01:00
istream libstdc++: Fix constraints for rvalue stream insertion/extraction 2021-05-07 23:45:52 +01:00
iterator
latch libstdc++: Fix whitespace in license boilerplate 2021-04-21 12:59:58 +01:00
limits
list
locale
map
memory libstdc++: Fix even more doxygen markup for group close commands 2021-04-09 13:09:23 +01:00
memory_resource libstdc++: Add warnings for some C++23 deprecations 2021-06-09 10:32:43 +01:00
mutex libstdc++: Improve std::lock algorithm 2021-06-21 18:29:58 +01:00
numbers
numeric libstdc++: Replace incorrect static assertion in std::reduce [PR95833] 2021-06-18 14:46:58 +01:00
optional libstdc++: Fix constraint on std::optional assignment [PR 100982] 2021-06-09 12:45:11 +01:00
ostream libstdc++: Fix constraints for rvalue stream insertion/extraction 2021-05-07 23:45:52 +01:00
queue
random
ranges libstdc++: Implement new views::split as per P2210 2021-06-20 12:47:18 -04:00
ratio libstdc++: Fix doxygen markup for group close commands 2021-04-06 16:43:24 +01:00
regex
scoped_allocator
semaphore libstdc++: Remove #error from <semaphore> implementation [PR 100179] 2021-04-22 13:59:32 +01:00
set
shared_mutex libstdc++: Fix doxygen markup for group close commands 2021-04-06 16:43:24 +01:00
source_location
span libstdc++: Implement P2325 changes to default-constructibility of views 2021-06-17 22:29:03 -04:00
sstream
stack
stdexcept libstdc++: Fix doxygen markup for group close commands 2021-04-06 16:43:24 +01:00
stop_token libstdc++: Remove TODO comment 2021-05-10 21:10:34 +01:00
streambuf libstdc++: Fix doxygen markup for group close commands 2021-04-06 16:43:24 +01:00
string
string_view libstdc++: Fix Doxygen warning about ambiguous file name 2021-04-08 14:51:03 +01:00
syncstream
system_error libstdc++: Fix doxygen markup for group close commands 2021-04-06 16:43:24 +01:00
thread libstdc++: Fix std::jthread assertion and re-enable skipped test 2021-05-17 17:56:57 +01:00
tuple libstdc++: Use reserved name for attribute [PR101055] 2021-06-14 11:53:29 +01:00
type_traits libstdc++: Fix common_reference for non-reference results [PR100894] 2021-06-14 21:17:53 +01:00
typeindex
unordered_map
unordered_set
utility libstdc++: Add nodiscard attribute to cast-like functions 2021-04-06 16:43:25 +01:00
valarray libstdc++: Fix doxygen markup for group close commands 2021-04-06 16:43:24 +01:00
variant libstdc++: Do not use deduced return type for std::visit [PR 100384] 2021-05-04 12:16:46 +01:00
vector
version libstdc++: Implement P2325 changes to default-constructibility of views 2021-06-17 22:29:03 -04:00