1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: no-threads 10 // UNSUPPORTED: c++03, c++11, c++14 11 12 // <shared_mutex> 13 14 // class shared_mutex; 15 16 // void lock(); 17 18 #include <shared_mutex> 19 #include <atomic> 20 #include <cassert> 21 #include <chrono> 22 #include <thread> 23 #include <vector> 24 25 #include "make_test_thread.h" 26 #include "test_macros.h" 27 28 int main(int, char**) { 29 // Exclusive-lock a mutex that is not locked yet. This should succeed. 30 { 31 std::shared_mutex m; 32 m.lock(); 33 m.unlock(); 34 } 35 36 // Exclusive-lock a mutex that is already locked exclusively. This should block until it is unlocked. 37 { 38 std::atomic<bool> ready(false); 39 std::shared_mutex m; 40 m.lock(); 41 std::atomic<bool> is_locked_from_main(true); 42 43 std::thread t = support::make_test_thread([&] { 44 ready = true; 45 m.lock(); 46 assert(!is_locked_from_main); 47 m.unlock(); 48 }); 49 50 while (!ready) 51 /* spin */; 52 53 // We would rather signal this after we unlock, but that would create a race condition. 54 // We instead signal it before we unlock, which means that it's technically possible for the thread 55 // to take the lock while we're still holding it and for the test to still pass. 56 is_locked_from_main = false; 57 m.unlock(); 58 59 t.join(); 60 } 61 62 // Exclusive-lock a mutex that is already share-locked. This should block until it is unlocked. 63 { 64 std::atomic<bool> ready(false); 65 std::shared_mutex m; 66 m.lock_shared(); 67 std::atomic<bool> is_locked_from_main(true); 68 69 std::thread t = support::make_test_thread([&] { 70 ready = true; 71 m.lock(); 72 assert(!is_locked_from_main); 73 m.unlock(); 74 }); 75 76 while (!ready) 77 /* spin */; 78 79 // We would rather signal this after we unlock, but that would create a race condition. 80 // We instead signal it before we unlock, which means that it's technically possible for 81 // the thread to take the lock while we're still holding it and for the test to still pass. 82 is_locked_from_main = false; 83 m.unlock_shared(); 84 85 t.join(); 86 } 87 88 // Make sure that at most one thread can acquire the mutex concurrently. 89 { 90 std::atomic<int> counter = 0; 91 std::shared_mutex mutex; 92 93 std::vector<std::thread> threads; 94 for (int i = 0; i != 10; ++i) { 95 threads.push_back(support::make_test_thread([&] { 96 mutex.lock(); 97 counter++; 98 assert(counter == 1); 99 counter--; 100 mutex.unlock(); 101 })); 102 } 103 104 for (auto& t : threads) 105 t.join(); 106 } 107 108 return 0; 109 } 110