diff --git a/docs/api.rst b/docs/api.rst index d319e5660..eab842609 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -39,7 +39,6 @@ These headers are part of the public API, but are currently undocumented. - ``pika/mutex.hpp`` - ``pika/runtime.hpp`` - ``pika/semaphore.hpp`` -- ``pika/shared_mutex.hpp`` - ``pika/thread.hpp`` All functionality in a namespace containing ``detail`` and all macros prefixed with ``PIKA_DETAIL`` diff --git a/examples/quickstart/CMakeLists.txt b/examples/quickstart/CMakeLists.txt index 422c3d331..100be496f 100644 --- a/examples/quickstart/CMakeLists.txt +++ b/examples/quickstart/CMakeLists.txt @@ -13,8 +13,6 @@ set(example_programs hello_world latch_example # suffix added to avoid conflict with unit tests pipeline1 - # shared_mutex # Disabled due to unavailable timed suspension timed_wake # Disabled due to - # unavailable timed suspension use_main_thread ) diff --git a/examples/quickstart/shared_mutex.cpp b/examples/quickstart/shared_mutex.cpp deleted file mode 100644 index 134f5f481..000000000 --- a/examples/quickstart/shared_mutex.cpp +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2015 Hartmut Kaiser -// -// SPDX-License-Identifier: BSL-1.0 -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// This example was released to the public domain by Stephan T. Lavavej -// (see: https://channel9.msdn.com/Shows/C9-GoingNative/GoingNative-40-Updated-STL-in-VS-2015-feat-STL) - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int const writers = 3; -int const readers = 3; -int const cycles = 10; - -using std::chrono::milliseconds; - -int pika_main() -{ - std::vector threads; - std::atomic ready(false); - pika::shared_mutex stm; - - for (int i = 0; i < writers; ++i) - { - threads.emplace_back([&ready, &stm, i] { - std::mt19937 urng(static_cast(std::time(nullptr))); - std::uniform_int_distribution dist(1, 1000); - - while (!ready) - { /*** wait... ***/ - } - - for (int j = 0; j < cycles; ++j) - { - std::unique_lock ul(stm); - - std::cout << "^^^ Writer " << i << " starting..." << std::endl; - pika::this_thread::sleep_for(milliseconds(dist(urng))); - std::cout << "vvv Writer " << i << " finished." << std::endl; - - ul.unlock(); - - pika::this_thread::sleep_for(milliseconds(dist(urng))); - } - }); - } - - for (int i = 0; i < readers; ++i) - { - threads.emplace_back([&ready, &stm, i] { - std::mt19937 urng(static_cast(std::time(nullptr))); - std::uniform_int_distribution dist(1, 1000); - - while (!ready) - { /*** wait... ***/ - } - - for (int j = 0; j < cycles; ++j) - { - std::shared_lock sl(stm); - - std::cout << "Reader " << i << " starting..." << std::endl; - pika::this_thread::sleep_for(milliseconds(dist(urng))); - std::cout << "Reader " << i << " finished." << std::endl; - - sl.unlock(); - - pika::this_thread::sleep_for(milliseconds(dist(urng))); - } - }); - } - - ready = true; - for (auto& t : threads) t.join(); - - pika::finalize(); - return EXIT_SUCCESS; -} - -int main(int argc, char* argv[]) { return pika::init(pika_main, argc, argv); } diff --git a/libs/pika/include/CMakeLists.txt b/libs/pika/include/CMakeLists.txt index 780c63d59..69bb9ea8f 100644 --- a/libs/pika/include/CMakeLists.txt +++ b/libs/pika/include/CMakeLists.txt @@ -18,7 +18,6 @@ set(include_headers pika/mutex.hpp pika/runtime.hpp pika/semaphore.hpp - pika/shared_mutex.hpp pika/stop_token.hpp pika/system_error.hpp pika/thread.hpp diff --git a/libs/pika/include/include/pika/shared_mutex.hpp b/libs/pika/include/include/pika/shared_mutex.hpp deleted file mode 100644 index e6fd69b82..000000000 --- a/libs/pika/include/include/pika/shared_mutex.hpp +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2020 ETH Zurich -// -// SPDX-License-Identifier: BSL-1.0 -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#pragma once - -#include -#include diff --git a/libs/pika/synchronization/CMakeLists.txt b/libs/pika/synchronization/CMakeLists.txt index a21ca0728..25b96a6e8 100644 --- a/libs/pika/synchronization/CMakeLists.txt +++ b/libs/pika/synchronization/CMakeLists.txt @@ -25,7 +25,6 @@ set(synchronization_headers pika/synchronization/no_mutex.hpp pika/synchronization/once.hpp pika/synchronization/recursive_mutex.hpp - pika/synchronization/shared_mutex.hpp pika/synchronization/sliding_semaphore.hpp pika/synchronization/stop_token.hpp ) diff --git a/libs/pika/synchronization/docs/index.rst b/libs/pika/synchronization/docs/index.rst index ab8606427..1314a2c91 100644 --- a/libs/pika/synchronization/docs/index.rst +++ b/libs/pika/synchronization/docs/index.rst @@ -23,7 +23,6 @@ the C++ standard ones in |pika| threads: * :cpp:class:`pika::no_mutex` * :cpp:class:`pika::once_flag` * :cpp:class:`pika::recursive_mutex` -* :cpp:class:`pika::shared_mutex` * :cpp:class:`pika::sliding_semaphore` * :cpp:class:`pika::detail::spinlock_pool` diff --git a/libs/pika/synchronization/include/pika/synchronization/shared_mutex.hpp b/libs/pika/synchronization/include/pika/synchronization/shared_mutex.hpp deleted file mode 100644 index 7243a1433..000000000 --- a/libs/pika/synchronization/include/pika/synchronization/shared_mutex.hpp +++ /dev/null @@ -1,226 +0,0 @@ -// (C) Copyright 2006-2008 Anthony Williams -// (C) Copyright 2011 Bryce Lelbach -// -// SPDX-License-Identifier: BSL-1.0 -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#pragma once - -#include -#include -#include - -#include - -namespace pika::detail { - template - class shared_mutex - { - private: - using mutex_type = Mutex; - - struct state_data - { - unsigned shared_count; - bool exclusive; - bool upgrade; - bool exclusive_waiting_blocked; - }; - - state_data state; - mutex_type state_change; - pika::condition_variable shared_cond; - pika::condition_variable exclusive_cond; - pika::condition_variable upgrade_cond; - - void release_waiters() - { - exclusive_cond.notify_one(); - shared_cond.notify_all(); - } - - public: - shared_mutex() - : state{0u, false, false, false} - , shared_cond() - , exclusive_cond() - , upgrade_cond() - { - } - - void lock_shared() - { - std::unique_lock lk(state_change); - - shared_cond.wait( - lk, [&] { return !(state.exclusive || state.exclusive_waiting_blocked); }); - - ++state.shared_count; - } - - bool try_lock_shared() - { - std::unique_lock lk(state_change); - - if (state.exclusive || state.exclusive_waiting_blocked) - return false; - - else - { - ++state.shared_count; - return true; - } - } - - void unlock_shared() - { - std::unique_lock lk(state_change); - - bool const last_reader = !--state.shared_count; - - if (last_reader) - { - if (state.upgrade) - { - state.upgrade = false; - state.exclusive = true; - - upgrade_cond.notify_one(); - } - else { state.exclusive_waiting_blocked = false; } - - release_waiters(); - } - } - - void lock() - { - std::unique_lock lk(state_change); - - exclusive_cond.wait(lk, [&] { - state.exclusive_waiting_blocked = true; - return !(state.shared_count || state.exclusive); - }); - - state.exclusive = true; - } - - bool try_lock() - { - std::unique_lock lk(state_change); - - if (state.shared_count || state.exclusive) - return false; - - else - { - state.exclusive = true; - return true; - } - } - - void unlock() - { - std::unique_lock lk(state_change); - state.exclusive = false; - state.exclusive_waiting_blocked = false; - release_waiters(); - } - - void lock_upgrade() - { - std::unique_lock lk(state_change); - - shared_cond.wait(lk, [&] { - return !(state.exclusive || state.exclusive_waiting_blocked || state.upgrade); - }); - - ++state.shared_count; - state.upgrade = true; - } - - bool try_lock_upgrade() - { - std::unique_lock lk(state_change); - - if (state.exclusive || state.exclusive_waiting_blocked || state.upgrade) - return false; - - else - { - ++state.shared_count; - state.upgrade = true; - return true; - } - } - - void unlock_upgrade() - { - std::unique_lock lk(state_change); - state.upgrade = false; - bool const last_reader = !--state.shared_count; - - if (last_reader) - { - state.exclusive_waiting_blocked = false; - release_waiters(); - } - } - - void unlock_upgrade_and_lock() - { - std::unique_lock lk(state_change); - --state.shared_count; - - upgrade_cond.wait(lk, [&] { return !state.shared_count; }); - - state.upgrade = false; - state.exclusive = true; - } - - void unlock_and_lock_upgrade() - { - std::unique_lock lk(state_change); - state.exclusive = false; - state.upgrade = true; - ++state.shared_count; - state.exclusive_waiting_blocked = false; - release_waiters(); - } - - void unlock_and_lock_shared() - { - std::unique_lock lk(state_change); - state.exclusive = false; - ++state.shared_count; - state.exclusive_waiting_blocked = false; - release_waiters(); - } - - bool try_unlock_shared_and_lock() - { - std::unique_lock lk(state_change); - if (!state.exclusive && !state.exclusive_waiting_blocked && !state.upgrade && - state.shared_count == 1) - { - state.shared_count = 0; - state.exclusive = true; - return true; - } - return false; - } - - void unlock_upgrade_and_lock_shared() - { - std::unique_lock lk(state_change); - state.upgrade = false; - state.exclusive_waiting_blocked = false; - release_waiters(); - } - }; -} // namespace pika::detail - -namespace pika { - using shared_mutex = detail::shared_mutex<>; -} diff --git a/libs/pika/synchronization/tests/regressions/CMakeLists.txt b/libs/pika/synchronization/tests/regressions/CMakeLists.txt index 4d458e7b3..926e3cbc9 100644 --- a/libs/pika/synchronization/tests/regressions/CMakeLists.txt +++ b/libs/pika/synchronization/tests/regressions/CMakeLists.txt @@ -4,10 +4,8 @@ # Distributed under the Boost Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -set(tests ignore_while_locked_1485 shared_mutex_1702) +set(tests ignore_while_locked_1485) -set(shared_mutex_1702_PARAMETERS THREADS 4) -set(shared_mutex_1702_LIBRARIES pika_dependencies_boost) set(ignore_while_locked_1485_PARAMETERS THREADS 2) # Create test cases diff --git a/libs/pika/synchronization/tests/regressions/shared_mutex_1702.cpp b/libs/pika/synchronization/tests/regressions/shared_mutex_1702.cpp deleted file mode 100644 index 301f64335..000000000 --- a/libs/pika/synchronization/tests/regressions/shared_mutex_1702.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2015 Hartmut Kaiser -// -// SPDX-License-Identifier: BSL-1.0 -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// This test case demonstrates the issue described in #1702: Shared_mutex does -// not compile with no_mutex cond_var - -#include -#include -#include - -#include -#include -#include - -int pika_main() -{ - using shared_mutex_type = pika::shared_mutex; - - int data = 0; - shared_mutex_type mtx; - - { - std::unique_lock l(mtx); - data = 42; - } - - { - std::shared_lock l(mtx); - [[maybe_unused]] int i = data; - } - - pika::finalize(); - return EXIT_SUCCESS; -} - -int main(int argc, char* argv[]) -{ - PIKA_TEST_EQ_MSG(pika::init(pika_main, argc, argv), 0, "pika main exited with non-zero status"); - - return 0; -} diff --git a/libs/pika/synchronization/tests/unit/CMakeLists.txt b/libs/pika/synchronization/tests/unit/CMakeLists.txt index b2f65b2f9..aefc0f968 100644 --- a/libs/pika/synchronization/tests/unit/CMakeLists.txt +++ b/libs/pika/synchronization/tests/unit/CMakeLists.txt @@ -91,15 +91,3 @@ if(PIKA_WITH_COMPILE_ONLY_TESTS) endforeach() endif() - -# ################################################################################################## -set(subdirs shared_mutex) - -# add sub directories -foreach(subdir ${subdirs}) - pika_add_pseudo_target(tests.unit.modules.synchronization.${subdir}) - add_subdirectory(${subdir}) - pika_add_pseudo_dependencies( - tests.unit.modules.synchronization tests.unit.modules.synchronization.${subdir} - ) -endforeach() diff --git a/libs/pika/synchronization/tests/unit/shared_mutex/CMakeLists.txt b/libs/pika/synchronization/tests/unit/shared_mutex/CMakeLists.txt deleted file mode 100644 index 7d5504f7e..000000000 --- a/libs/pika/synchronization/tests/unit/shared_mutex/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2015 Hartmut Kaiser -# -# SPDX-License-Identifier: BSL-1.0 -# Distributed under the Boost Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -set(tests shared_mutex1 shared_mutex2) - -set(shared_mutex1_PARAMETERS THREADS 4) -set(shared_mutex2_PARAMETERS THREADS 4) - -set(shared_mutex1_FLAGS DEPENDENCIES PRIVATE pika_dependencies_boost) - -foreach(test ${tests}) - set(sources ${test}.cpp) - - source_group("Source Files" FILES ${sources}) - - # add example executable - pika_add_executable( - ${test}_test INTERNAL_FLAGS - SOURCES ${sources} ${${test}_FLAGS} - EXCLUDE_FROM_ALL - FOLDER "Tests/Unit/Modules/Synchronization/SharedMutex" - ) - - pika_add_unit_test("modules.synchronization.shared_mutex" ${test} ${${test}_PARAMETERS}) - -endforeach() diff --git a/libs/pika/synchronization/tests/unit/shared_mutex/shared_mutex1.cpp b/libs/pika/synchronization/tests/unit/shared_mutex/shared_mutex1.cpp deleted file mode 100644 index 48c5d60c7..000000000 --- a/libs/pika/synchronization/tests/unit/shared_mutex/shared_mutex1.cpp +++ /dev/null @@ -1,328 +0,0 @@ -// (C) Copyright 2006-7 Anthony Williams -// Copyright (c) 2015 Hartmut Kaiser -// -// SPDX-License-Identifier: BSL-1.0 -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "shared_mutex_locking_thread.hpp" -#include "thread_group.hpp" - -#define CHECK_LOCKED_VALUE_EQUAL(mutex_name, value, expected_value) \ - { \ - std::unique_lock lock(mutex_name); \ - PIKA_TEST_EQ(value, expected_value); \ - } - -void test_multiple_readers() -{ - using shared_mutex_type = pika::shared_mutex; - using mutex_type = pika::mutex; - - unsigned const number_of_threads = 10; - - test::thread_group pool; - - pika::shared_mutex rw_mutex; - unsigned unblocked_count = 0; - unsigned simultaneous_running_count = 0; - unsigned max_simultaneous_running = 0; - mutex_type unblocked_count_mutex; - pika::condition_variable unblocked_condition; - mutex_type finish_mutex; - std::unique_lock finish_lock(finish_mutex); - - try - { - for (unsigned i = 0; i != number_of_threads; ++i) - { - pool.create_thread(test::locking_thread>(rw_mutex, - unblocked_count, unblocked_count_mutex, unblocked_condition, finish_mutex, - simultaneous_running_count, max_simultaneous_running)); - } - - { - std::unique_lock lk(unblocked_count_mutex); - unblocked_condition.wait(lk, [&] { return unblocked_count >= number_of_threads; }); - } - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, unblocked_count, number_of_threads); - - finish_lock.unlock(); - pool.join_all(); - } - catch (...) - { - pool.interrupt_all(); - pool.join_all(); - PIKA_TEST(false); - } - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, max_simultaneous_running, number_of_threads); -} - -void test_only_one_writer_permitted() -{ - using shared_mutex_type = pika::shared_mutex; - using mutex_type = pika::mutex; - - unsigned const number_of_threads = 10; - - test::thread_group pool; - - pika::shared_mutex rw_mutex; - unsigned unblocked_count = 0; - unsigned simultaneous_running_count = 0; - unsigned max_simultaneous_running = 0; - mutex_type unblocked_count_mutex; - pika::condition_variable unblocked_condition; - mutex_type finish_mutex; - std::unique_lock finish_lock(finish_mutex); - - try - { - for (unsigned i = 0; i != number_of_threads; ++i) - { - pool.create_thread(test::locking_thread>(rw_mutex, - unblocked_count, unblocked_count_mutex, unblocked_condition, finish_mutex, - simultaneous_running_count, max_simultaneous_running)); - } - - pika::this_thread::yield(); - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, unblocked_count, 1u); - - finish_lock.unlock(); - pool.join_all(); - } - catch (...) - { - pool.interrupt_all(); - pool.join_all(); - PIKA_TEST(false); - } - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, unblocked_count, number_of_threads); - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, max_simultaneous_running, 1u); -} - -void test_reader_blocks_writer() -{ - using shared_mutex_type = pika::shared_mutex; - using mutex_type = pika::mutex; - - test::thread_group pool; - - pika::shared_mutex rw_mutex; - unsigned unblocked_count = 0; - unsigned simultaneous_running_count = 0; - unsigned max_simultaneous_running = 0; - mutex_type unblocked_count_mutex; - pika::condition_variable unblocked_condition; - mutex_type finish_mutex; - std::unique_lock finish_lock(finish_mutex); - - try - { - pool.create_thread(test::locking_thread>(rw_mutex, - unblocked_count, unblocked_count_mutex, unblocked_condition, finish_mutex, - simultaneous_running_count, max_simultaneous_running)); - - { - std::unique_lock lk(unblocked_count_mutex); - unblocked_condition.wait(lk, [&] { return unblocked_count >= 1; }); - } - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, unblocked_count, 1u); - - pool.create_thread(test::locking_thread>(rw_mutex, - unblocked_count, unblocked_count_mutex, unblocked_condition, finish_mutex, - simultaneous_running_count, max_simultaneous_running)); - - pika::this_thread::yield(); - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, unblocked_count, 1u); - - finish_lock.unlock(); - pool.join_all(); - } - catch (...) - { - pool.interrupt_all(); - pool.join_all(); - PIKA_TEST(false); - } - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, unblocked_count, 2u); - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, max_simultaneous_running, 1u); -} - -void test_unlocking_writer_unblocks_all_readers() -{ - using shared_mutex_type = pika::shared_mutex; - using mutex_type = pika::mutex; - - test::thread_group pool; - - pika::shared_mutex rw_mutex; - std::unique_lock write_lock(rw_mutex); - unsigned unblocked_count = 0; - unsigned simultaneous_running_count = 0; - unsigned max_simultaneous_running = 0; - mutex_type unblocked_count_mutex; - pika::condition_variable unblocked_condition; - mutex_type finish_mutex; - std::unique_lock finish_lock(finish_mutex); - - unsigned const reader_count = 10; - - try - { - for (unsigned i = 0; i != reader_count; ++i) - { - pool.create_thread(test::locking_thread>(rw_mutex, - unblocked_count, unblocked_count_mutex, unblocked_condition, finish_mutex, - simultaneous_running_count, max_simultaneous_running)); - } - - pika::this_thread::yield(); - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, unblocked_count, 0u); - - write_lock.unlock(); - - { - std::unique_lock lk(unblocked_count_mutex); - unblocked_condition.wait(lk, [&] { return unblocked_count >= reader_count; }); - } - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, unblocked_count, reader_count); - - finish_lock.unlock(); - pool.join_all(); - } - catch (...) - { - pool.interrupt_all(); - pool.join_all(); - PIKA_TEST(false); - } - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, max_simultaneous_running, reader_count); -} - -void test_unlocking_last_reader_only_unblocks_one_writer() -{ - using shared_mutex_type = pika::shared_mutex; - using mutex_type = pika::mutex; - - test::thread_group pool; - - pika::shared_mutex rw_mutex; - unsigned unblocked_count = 0; - unsigned simultaneous_running_readers = 0; - unsigned max_simultaneous_readers = 0; - unsigned simultaneous_running_writers = 0; - unsigned max_simultaneous_writers = 0; - mutex_type unblocked_count_mutex; - pika::condition_variable unblocked_condition; - mutex_type finish_reading_mutex; - std::unique_lock finish_reading_lock(finish_reading_mutex); - mutex_type finish_writing_mutex; - std::unique_lock finish_writing_lock(finish_writing_mutex); - - unsigned const reader_count = 10; - unsigned const writer_count = 10; - - try - { - for (unsigned i = 0; i != reader_count; ++i) - { - pool.create_thread(test::locking_thread>(rw_mutex, - unblocked_count, unblocked_count_mutex, unblocked_condition, finish_reading_mutex, - simultaneous_running_readers, max_simultaneous_readers)); - } - - std::this_thread::sleep_for(std::chrono::seconds(1)); - pika::this_thread::yield(); - - for (unsigned i = 0; i != writer_count; ++i) - { - pool.create_thread(test::locking_thread>(rw_mutex, - unblocked_count, unblocked_count_mutex, unblocked_condition, finish_writing_mutex, - simultaneous_running_writers, max_simultaneous_writers)); - } - - { - std::unique_lock lk(unblocked_count_mutex); - unblocked_condition.wait(lk, [&] { return unblocked_count >= reader_count; }); - } - - std::this_thread::sleep_for(std::chrono::seconds(1)); - pika::this_thread::yield(); - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, unblocked_count, reader_count); - - finish_reading_lock.unlock(); - - { - std::unique_lock lk(unblocked_count_mutex); - unblocked_condition.wait(lk, [&] { return unblocked_count >= reader_count + 1; }); - } - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, unblocked_count, reader_count + 1); - - finish_writing_lock.unlock(); - pool.join_all(); - } - catch (...) - { - pool.interrupt_all(); - pool.join_all(); - PIKA_TEST(false); - } - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, unblocked_count, reader_count + writer_count); - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, max_simultaneous_readers, reader_count); - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, max_simultaneous_writers, 1u); -} - -/////////////////////////////////////////////////////////////////////////////// -int pika_main() -{ - test_multiple_readers(); - test_only_one_writer_permitted(); - test_reader_blocks_writer(); - test_unlocking_writer_unblocks_all_readers(); - test_unlocking_last_reader_only_unblocks_one_writer(); - - pika::finalize(); - return EXIT_SUCCESS; -} - -int main(int argc, char* argv[]) -{ - // By default this test should run on all available cores - std::vector const cfg = {"pika.os_threads=all"}; - - // Initialize and run pika - pika::init_params init_args; - init_args.cfg = cfg; - PIKA_TEST_EQ_MSG( - pika::init(pika_main, argc, argv, init_args), 0, "pika main exited with non-zero status"); - - return 0; -} diff --git a/libs/pika/synchronization/tests/unit/shared_mutex/shared_mutex2.cpp b/libs/pika/synchronization/tests/unit/shared_mutex/shared_mutex2.cpp deleted file mode 100644 index aa2eedce1..000000000 --- a/libs/pika/synchronization/tests/unit/shared_mutex/shared_mutex2.cpp +++ /dev/null @@ -1,296 +0,0 @@ -// (C) Copyright 2006-7 Anthony Williams -// Copyright (c) 2015 Hartmut Kaiser -// -// SPDX-License-Identifier: BSL-1.0 -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "shared_mutex_locking_thread.hpp" -#include "thread_group.hpp" - -#define CHECK_LOCKED_VALUE_EQUAL(mutex_name, value, expected_value) \ - { \ - std::unique_lock lock(mutex_name); \ - PIKA_TEST_EQ(value, expected_value); \ - } - -void test_only_one_upgrade_lock_permitted() -{ - using shared_mutex_type = pika::shared_mutex; - using mutex_type = pika::mutex; - - unsigned const number_of_threads = 2; - - test::thread_group pool; - - shared_mutex_type rw_mutex; - unsigned unblocked_count = 0; - unsigned simultaneous_running_count = 0; - unsigned max_simultaneous_running = 0; - mutex_type unblocked_count_mutex; - pika::condition_variable unblocked_condition; - mutex_type finish_mutex; - std::unique_lock finish_lock(finish_mutex); - - try - { - for (unsigned i = 0; i != number_of_threads; ++i) - { - pool.create_thread(test::locking_thread>(rw_mutex, - unblocked_count, unblocked_count_mutex, unblocked_condition, finish_mutex, - simultaneous_running_count, max_simultaneous_running)); - } - - // Wait for one of the threads to signal that it is unblocked - { - std::unique_lock lk(unblocked_count_mutex); - unblocked_condition.wait(lk, [&]() { return unblocked_count >= 1u; }); - } - - // Wait a moment to see if the second thread gets the lock concurrently - // (it should not) - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, unblocked_count, 1u); - - finish_lock.unlock(); - pool.join_all(); - } - catch (...) - { - pool.interrupt_all(); - pool.join_all(); - PIKA_TEST(false); - } - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, unblocked_count, number_of_threads); - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, max_simultaneous_running, 1u); -} - -void test_can_lock_upgrade_if_currently_locked_shared() -{ - using shared_mutex_type = pika::shared_mutex; - using mutex_type = pika::mutex; - - test::thread_group pool; - - shared_mutex_type rw_mutex; - unsigned unblocked_count = 0; - unsigned simultaneous_running_count = 0; - unsigned max_simultaneous_running = 0; - mutex_type unblocked_count_mutex; - pika::condition_variable unblocked_condition; - mutex_type finish_mutex; - std::unique_lock finish_lock(finish_mutex); - - unsigned const reader_count = 10; - - try - { - for (unsigned i = 0; i != reader_count; ++i) - { - pool.create_thread(test::locking_thread>(rw_mutex, - unblocked_count, unblocked_count_mutex, unblocked_condition, finish_mutex, - simultaneous_running_count, max_simultaneous_running)); - } - - pika::this_thread::yield(); - - pool.create_thread(test::locking_thread>(rw_mutex, - unblocked_count, unblocked_count_mutex, unblocked_condition, finish_mutex, - simultaneous_running_count, max_simultaneous_running)); - - { - std::unique_lock lk(unblocked_count_mutex); - unblocked_condition.wait(lk, [&] { return unblocked_count >= reader_count + 1; }); - } - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, unblocked_count, reader_count + 1); - - finish_lock.unlock(); - pool.join_all(); - } - catch (...) - { - pool.interrupt_all(); - pool.join_all(); - PIKA_TEST(false); - } - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, unblocked_count, reader_count + 1); - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex, max_simultaneous_running, reader_count + 1); -} - -void test_can_lock_upgrade_to_unique_if_currently_locked_upgrade() -{ - using shared_mutex_type = pika::shared_mutex; - - shared_mutex_type mtx; - pika::upgrade_lock l(mtx); - pika::upgrade_to_unique_lock ul(l); - PIKA_TEST(ul.owns_lock()); -} - -void test_if_other_thread_has_write_lock_try_lock_shared_returns_false() -{ - using shared_mutex_type = pika::shared_mutex; - using mutex_type = pika::mutex; - - shared_mutex_type rw_mutex; - mutex_type finish_mutex; - mutex_type unblocked_mutex; - unsigned unblocked_count = 0; - std::unique_lock finish_lock(finish_mutex); - pika::thread writer( - test::simple_writing_thread(rw_mutex, finish_mutex, unblocked_mutex, unblocked_count)); - - std::this_thread::sleep_for(std::chrono::seconds(1)); - - CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex, unblocked_count, 1u); - - bool const try_succeeded = rw_mutex.try_lock_shared(); - PIKA_TEST(!try_succeeded); - if (try_succeeded) { rw_mutex.unlock_shared(); } - - finish_lock.unlock(); - writer.join(); -} - -void test_if_other_thread_has_write_lock_try_lock_upgrade_returns_false() -{ - using shared_mutex_type = pika::shared_mutex; - using mutex_type = pika::mutex; - - shared_mutex_type rw_mutex; - mutex_type finish_mutex; - mutex_type unblocked_mutex; - unsigned unblocked_count = 0; - std::unique_lock finish_lock(finish_mutex); - pika::thread writer( - test::simple_writing_thread(rw_mutex, finish_mutex, unblocked_mutex, unblocked_count)); - - std::this_thread::sleep_for(std::chrono::seconds(1)); - - CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex, unblocked_count, 1u); - - bool const try_succeeded = rw_mutex.try_lock_upgrade(); - PIKA_TEST(!try_succeeded); - if (try_succeeded) { rw_mutex.unlock_upgrade(); } - - finish_lock.unlock(); - writer.join(); -} - -void test_if_no_thread_has_lock_try_lock_shared_returns_true() -{ - using shared_mutex_type = pika::shared_mutex; - - shared_mutex_type rw_mutex; - bool const try_succeeded = rw_mutex.try_lock_shared(); - PIKA_TEST(try_succeeded); - if (try_succeeded) { rw_mutex.unlock_shared(); } -} - -void test_if_no_thread_has_lock_try_lock_upgrade_returns_true() -{ - using shared_mutex_type = pika::shared_mutex; - - shared_mutex_type rw_mutex; - bool const try_succeeded = rw_mutex.try_lock_upgrade(); - PIKA_TEST(try_succeeded); - if (try_succeeded) { rw_mutex.unlock_upgrade(); } -} - -void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true() -{ - using shared_mutex_type = pika::shared_mutex; - using mutex_type = pika::mutex; - - shared_mutex_type rw_mutex; - mutex_type finish_mutex; - mutex_type unblocked_mutex; - unsigned unblocked_count = 0; - std::unique_lock finish_lock(finish_mutex); - pika::thread writer( - test::simple_reading_thread(rw_mutex, finish_mutex, unblocked_mutex, unblocked_count)); - - std::this_thread::sleep_for(std::chrono::seconds(1)); - - CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex, unblocked_count, 1u); - - bool const try_succeeded = rw_mutex.try_lock_shared(); - PIKA_TEST(try_succeeded); - if (try_succeeded) { rw_mutex.unlock_shared(); } - - finish_lock.unlock(); - writer.join(); -} - -void test_if_other_thread_has_shared_lock_try_lock_upgrade_returns_true() -{ - using shared_mutex_type = pika::shared_mutex; - using mutex_type = pika::mutex; - - shared_mutex_type rw_mutex; - mutex_type finish_mutex; - mutex_type unblocked_mutex; - unsigned unblocked_count = 0; - std::unique_lock finish_lock(finish_mutex); - pika::thread writer( - test::simple_reading_thread(rw_mutex, finish_mutex, unblocked_mutex, unblocked_count)); - - std::this_thread::sleep_for(std::chrono::seconds(1)); - - CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex, unblocked_count, 1u); - - bool const try_succeeded = rw_mutex.try_lock_upgrade(); - PIKA_TEST(try_succeeded); - if (try_succeeded) { rw_mutex.unlock_upgrade(); } - - finish_lock.unlock(); - writer.join(); -} - -/////////////////////////////////////////////////////////////////////////////// -int pika_main() -{ - test_only_one_upgrade_lock_permitted(); - test_can_lock_upgrade_if_currently_locked_shared(); - test_can_lock_upgrade_to_unique_if_currently_locked_upgrade(); - test_if_other_thread_has_write_lock_try_lock_shared_returns_false(); - test_if_other_thread_has_write_lock_try_lock_upgrade_returns_false(); - test_if_no_thread_has_lock_try_lock_shared_returns_true(); - test_if_no_thread_has_lock_try_lock_upgrade_returns_true(); - test_if_other_thread_has_shared_lock_try_lock_shared_returns_true(); - test_if_other_thread_has_shared_lock_try_lock_upgrade_returns_true(); - - pika::finalize(); - return EXIT_SUCCESS; -} - -int main(int argc, char* argv[]) -{ - // By default this test should run on all available cores - std::vector const cfg = {"pika.os_threads=all"}; - - // Initialize and run pika - pika::init_params init_args; - init_args.cfg = cfg; - PIKA_TEST_EQ_MSG( - pika::init(pika_main, argc, argv, init_args), 0, "pika main exited with non-zero status"); - - return 0; -} diff --git a/libs/pika/synchronization/tests/unit/shared_mutex/shared_mutex_locking_thread.hpp b/libs/pika/synchronization/tests/unit/shared_mutex/shared_mutex_locking_thread.hpp deleted file mode 100644 index 2cebe8313..000000000 --- a/libs/pika/synchronization/tests/unit/shared_mutex/shared_mutex_locking_thread.hpp +++ /dev/null @@ -1,134 +0,0 @@ -// (C) Copyright 2008 Anthony Williams -// Copyright (c) 2015 Hartmut Kaiser -// -// SPDX-License-Identifier: BSL-1.0 -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#pragma once - -#include -#include -#include -#include - -#include -#include - -namespace test { - template - class locking_thread - { - private: - pika::shared_mutex& rw_mutex; - unsigned& unblocked_count; - pika::condition_variable& unblocked_condition; - unsigned& simultaneous_running_count; - unsigned& max_simultaneous_running; - pika::mutex& unblocked_count_mutex; - pika::mutex& finish_mutex; - - public: - locking_thread(pika::shared_mutex& rw_mutex_, unsigned& unblocked_count_, - pika::mutex& unblocked_count_mutex_, pika::condition_variable& unblocked_condition_, - pika::mutex& finish_mutex_, unsigned& simultaneous_running_count_, - unsigned& max_simultaneous_running_) - : rw_mutex(rw_mutex_) - , unblocked_count(unblocked_count_) - , unblocked_condition(unblocked_condition_) - , simultaneous_running_count(simultaneous_running_count_) - , max_simultaneous_running(max_simultaneous_running_) - , unblocked_count_mutex(unblocked_count_mutex_) - , finish_mutex(finish_mutex_) - { - } - - void operator()() - { - // acquire lock - Lock lock(rw_mutex); - - // increment count to show we're unblocked - { - std::unique_lock ublock(unblocked_count_mutex); - - ++unblocked_count; - unblocked_condition.notify_one(); - ++simultaneous_running_count; - if (simultaneous_running_count > max_simultaneous_running) - { - max_simultaneous_running = simultaneous_running_count; - } - } - - // wait to finish - std::unique_lock finish_lock(finish_mutex); - { - std::unique_lock ublock(unblocked_count_mutex); - - --simultaneous_running_count; - } - } - }; - - /////////////////////////////////////////////////////////////////////////// - class simple_writing_thread - { - private: - pika::shared_mutex& rwm; - pika::mutex& finish_mutex; - pika::mutex& unblocked_mutex; - unsigned& unblocked_count; - - public: - simple_writing_thread(pika::shared_mutex& rwm_, pika::mutex& finish_mutex_, - pika::mutex& unblocked_mutex_, unsigned& unblocked_count_) - : rwm(rwm_) - , finish_mutex(finish_mutex_) - , unblocked_mutex(unblocked_mutex_) - , unblocked_count(unblocked_count_) - { - } - - void operator()() - { - std::unique_lock lk(rwm); - { - std::unique_lock ulk(unblocked_mutex); - ++unblocked_count; - } - std::unique_lock flk(finish_mutex); - } - }; - - /////////////////////////////////////////////////////////////////////////// - class simple_reading_thread - { - private: - pika::shared_mutex& rwm; - pika::mutex& finish_mutex; - pika::mutex& unblocked_mutex; - unsigned& unblocked_count; - - public: - simple_reading_thread(pika::shared_mutex& rwm_, pika::mutex& finish_mutex_, - pika::mutex& unblocked_mutex_, unsigned& unblocked_count_) - : rwm(rwm_) - , finish_mutex(finish_mutex_) - , unblocked_mutex(unblocked_mutex_) - , unblocked_count(unblocked_count_) - { - } - - void operator()() - { - std::shared_lock lk(rwm); - { - std::unique_lock ulk(unblocked_mutex); - ++unblocked_count; - } - std::unique_lock flk(finish_mutex); - } - }; -} // namespace test diff --git a/libs/pika/synchronization/tests/unit/shared_mutex/thread_group.hpp b/libs/pika/synchronization/tests/unit/shared_mutex/thread_group.hpp deleted file mode 100644 index ee0de7759..000000000 --- a/libs/pika/synchronization/tests/unit/shared_mutex/thread_group.hpp +++ /dev/null @@ -1,143 +0,0 @@ -// (C) Copyright 2007-9 Anthony Williams -// Copyright (c) 2015 Hartmut Kaiser -// -// SPDX-License-Identifier: BSL-1.0 -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#pragma once - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#ifdef PIKA_MSVC -# pragma warning(push) -# pragma warning(disable : 4251) -#endif - -namespace test { - class thread_group - { - private: - using mutex_type = pika::shared_mutex; - - public: - thread_group() {} - - thread_group(thread_group const&) = delete; - thread_group& operator=(thread_group const&) = delete; - - ~thread_group() - { - for (pika::thread* t : threads) delete t; - } - - private: - bool is_this_thread_in() - { - pika::thread::id id = pika::this_thread::get_id(); - std::shared_lock guard(mtx_); - for (pika::thread* t : threads) - { - if (t->get_id() == id) return true; - } - return false; - } - - bool is_thread_in(pika::thread* thrd) - { - if (!thrd) return false; - - pika::thread::id id = thrd->get_id(); - std::shared_lock guard(mtx_); - for (pika::thread* t : threads) - { - if (t->get_id() == id) return true; - } - return false; - } - - public: - template - pika::thread* create_thread(F&& f) - { - std::lock_guard guard(mtx_); - std::unique_ptr new_thread(new pika::thread(PIKA_FORWARD(F, f))); - threads.push_back(new_thread.get()); - return new_thread.release(); - } - - void add_thread(pika::thread* thrd) - { - if (thrd) - { - if (is_thread_in(thrd)) - { - PIKA_THROW_EXCEPTION(pika::error::thread_resource_error, - "thread_group::add_thread", - "resource_deadlock_would_occur: trying to add a duplicated thread"); - return; - }; - - std::lock_guard guard(mtx_); - threads.push_back(thrd); - } - } - - void remove_thread(pika::thread* thrd) - { - std::lock_guard guard(mtx_); - std::list::iterator const it = - std::find(threads.begin(), threads.end(), thrd); - - if (it != threads.end()) threads.erase(it); - } - - void join_all() - { - if (is_this_thread_in()) - { - PIKA_THROW_EXCEPTION(pika::error::thread_resource_error, "thread_group::join_all", - "resource_deadlock_would_occur: trying joining itself"); - return; - } - - std::shared_lock guard(mtx_); - for (pika::thread* t : threads) - { - if (t->joinable()) t->join(); - } - } - - void interrupt_all() - { - std::shared_lock guard(mtx_); - for (pika::thread* t : threads) { t->interrupt(); } - } - - size_t size() const - { - std::shared_lock guard(mtx_); - return threads.size(); - } - - private: - std::list threads; - mutable mutex_type mtx_; - }; -} // namespace test - -#ifdef PIKA_MSVC -# pragma warning(pop) -#endif