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
28int 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

source code of libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.shared_mutex.requirements/thread.shared_mutex.class/lock.pass.cpp