diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2021-06-22 13:35:19 +0100 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2021-06-22 21:17:25 +0100 |
commit | c556596119307f9ef1c9079ef2bd3a035dea355d (patch) | |
tree | 0292d6d165df8828a851fe18b32cf4f2698dc3c0 /libstdc++-v3/testsuite/30_threads | |
parent | b5a29741db11007e37d8d4ff977b89a8314abfda (diff) | |
download | gcc-c556596119307f9ef1c9079ef2bd3a035dea355d.zip gcc-c556596119307f9ef1c9079ef2bd3a035dea355d.tar.gz gcc-c556596119307f9ef1c9079ef2bd3a035dea355d.tar.bz2 |
libstdc++: Simplify std::try_lock and std::lock further
The std::try_lock and std::lock algorithms can use iteration instead of
recursion when all lockables have the same type and can be held by an
array of unique_lock<L> objects.
By making this change to __detail::__try_lock_impl it also benefits
__detail::__lock_impl, which uses it. For std::lock we can just put the
iterative version directly in std::lock, to avoid making any call to
__detail::__lock_impl.
Signed-off-by: Matthias Kretz <m.kretz@gsi.de>
Signed-off-by: Jonathan Wakely <jwakely@redhat.com>
Co-authored-by: Matthias Kretz <m.kretz@gsi.de>
libstdc++-v3/ChangeLog:
* include/std/mutex (lock): Replace recursion with iteration
when lockables all have the same type.
(__detail::__try_lock_impl): Likewise. Pass lockables as
parameters, instead of a tuple. Always lock the first one, and
recurse for the rest.
(__detail::__lock_impl): Adjust call to __try_lock_impl.
(__detail::__try_to_lock): Remove.
* testsuite/30_threads/lock/3.cc: Check that mutexes are locked.
* testsuite/30_threads/lock/4.cc: Also test non-heterogeneous
arguments.
* testsuite/30_threads/unique_lock/cons/60497.cc: Also check
std::try_lock.
* testsuite/30_threads/try_lock/5.cc: New test.
Diffstat (limited to 'libstdc++-v3/testsuite/30_threads')
-rw-r--r-- | libstdc++-v3/testsuite/30_threads/lock/3.cc | 4 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/30_threads/lock/4.cc | 124 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/30_threads/try_lock/5.cc | 41 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc | 6 |
4 files changed, 174 insertions, 1 deletions
diff --git a/libstdc++-v3/testsuite/30_threads/lock/3.cc b/libstdc++-v3/testsuite/30_threads/lock/3.cc index 5213607..5fa1187 100644 --- a/libstdc++-v3/testsuite/30_threads/lock/3.cc +++ b/libstdc++-v3/testsuite/30_threads/lock/3.cc @@ -37,7 +37,7 @@ struct user_lock is_locked = true; } - bool try_lock() + bool try_lock() { return is_locked ? false : (is_locked = true); } void unlock() @@ -62,6 +62,8 @@ int main() { //heterogeneous types std::lock(m1, m2, m3); + VERIFY( !m1.try_lock() ); + VERIFY( !m3.try_lock() ); m1.unlock(); m2.unlock(); m3.unlock(); diff --git a/libstdc++-v3/testsuite/30_threads/lock/4.cc b/libstdc++-v3/testsuite/30_threads/lock/4.cc index 7ba15cb..130c1f6 100644 --- a/libstdc++-v3/testsuite/30_threads/lock/4.cc +++ b/libstdc++-v3/testsuite/30_threads/lock/4.cc @@ -73,6 +73,7 @@ int unreliable_lock::lock_on = -1; void test01() { unreliable_lock l1, l2, l3; + std::mutex m1, m2, m3; try { @@ -87,6 +88,60 @@ void test01() { VERIFY( false ); } + + // Repeat with non-heterogeneous arguments + + try + { + unreliable_lock::count = 0; + std::lock(l1, l2, l3, m1); + VERIFY( unreliable_lock::count == 3 ); + l1.unlock(); + l2.unlock(); + l3.unlock(); + VERIFY( !m1.try_lock() ); // already locked + m1.unlock(); + } + catch (...) + { + VERIFY( false ); + } + + try + { + unreliable_lock::count = 0; + std::lock(m1, l1, l2, l3); + VERIFY( unreliable_lock::count == 3 ); + VERIFY( !m1.try_lock() ); // already locked + m1.unlock(); + l1.unlock(); + l2.unlock(); + l3.unlock(); + } + catch (...) + { + VERIFY( false ); + } + + try + { + unreliable_lock::count = 0; + std::lock(l1, m1, l2, m2, l3, m3); + VERIFY( unreliable_lock::count == 3 ); + l1.unlock(); + l2.unlock(); + l3.unlock(); + VERIFY( !m1.try_lock() ); // already locked + VERIFY( !m2.try_lock() ); // already locked + VERIFY( !m3.try_lock() ); // already locked + m1.unlock(); + m2.unlock(); + m3.unlock(); + } + catch (...) + { + VERIFY( false ); + } } void test02() @@ -111,6 +166,31 @@ void test02() { VERIFY( false ); } + + // Repeat with non-heterogeneous arguments + + try + { + unreliable_lock::lock_on = 1; + while (unreliable_lock::lock_on < 3) + { + unreliable_lock::count = 0; + unreliable_lock l1, l2, l3; + std::mutex m1; + std::lock(l1, l2, l3, m1); + VERIFY( unreliable_lock::count > 3 ); + l1.unlock(); + l2.unlock(); + l3.unlock(); + VERIFY( !m1.try_lock() ); // already locked + m1.unlock(); + ++unreliable_lock::lock_on; + } + } + catch (...) + { + VERIFY( false ); + } } void test03() @@ -133,6 +213,50 @@ void test03() VERIFY( test ); ++unreliable_lock::throw_on; } + + // Repeat with non-heterogeneous arguments + + unreliable_lock::throw_on = 0; + while (unreliable_lock::throw_on < 3) + { + unreliable_lock::count = 0; + unreliable_lock l1, l2, l3; + std::mutex m1; + bool test = false; + try + { + std::lock(l1, l2, l3, m1); + } + catch (...) + { + test = true; + } + VERIFY( test ); + VERIFY( m1.try_lock() ); // m1 was not left locked by failed std::lock + m1.unlock(); + ++unreliable_lock::throw_on; + } + + unreliable_lock::throw_on = 0; + while (unreliable_lock::throw_on < 3) + { + unreliable_lock::count = 0; + unreliable_lock l1, l2, l3; + std::mutex m1; + bool test = false; + try + { + std::lock(m1, l1, l2, l3); + } + catch (...) + { + test = true; + } + VERIFY( test ); + VERIFY( m1.try_lock() ); // m1 was not left locked by failed std::lock + m1.unlock(); + ++unreliable_lock::throw_on; + } } int main() diff --git a/libstdc++-v3/testsuite/30_threads/try_lock/5.cc b/libstdc++-v3/testsuite/30_threads/try_lock/5.cc new file mode 100644 index 0000000..a5574ff --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/try_lock/5.cc @@ -0,0 +1,41 @@ +// { dg-do run { target c++11 } } + +#include <mutex> +#include <testsuite_hooks.h> + +struct Lockable +{ + static int tries; + + void lock() { } + void unlock() { } + bool try_lock() { return ++tries != 2; } +}; + +int Lockable::tries = 0; + +void test01() +{ + Lockable l1, l2, l3; + std::mutex m1, m2; + + VERIFY( std::try_lock(l1, l2, l3) == 1 ); + VERIFY( Lockable::tries == 2 ); + + Lockable::tries = 0; + VERIFY( std::try_lock(m1, l1, l2, l3) == 2 ); + VERIFY( Lockable::tries == 2 ); + + Lockable::tries = 0; + VERIFY( std::try_lock(l1, l2, l3, m1) == 1 ); + VERIFY( Lockable::tries == 2 ); + + Lockable::tries = 0; + VERIFY( std::try_lock(m1, l1, l2, l3, m2) == 2 ); + VERIFY( Lockable::tries == 2 ); +} + +int main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc b/libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc index 8603e56..08698ce 100644 --- a/libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc +++ b/libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc @@ -46,3 +46,9 @@ void test02() test_type l1, l2, l3; std::lock(l1, l2, l3); } + +void test03() +{ + test_type l1, l2, l3; + std::try_lock(l1, l2, l3); +} |