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 11 // <condition_variable> 12 13 // class condition_variable; 14 15 // void notify_one(); 16 17 18 // NOTE: `notify_one` is just a wrapper around pthread_cond_signal, but 19 // POSIX does not guarantee that one and only one thread will be woken: 20 // 21 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_signal.html 22 // 23 // Quote: 24 // Multiple Awakenings by Condition Signal 25 // On a multi-processor, it may be impossible for an implementation of 26 // pthread_cond_signal() to avoid the unblocking of more than one thread 27 // blocked on a condition variable. For example... 28 29 30 31 // NOTE: In previous versions of this test, `notify_one` was called WITHOUT 32 // holding the lock but POSIX says (in the aforementioned URL) that: 33 // ...if predictable scheduling behavior is required, then that mutex shall 34 // be locked by the thread calling pthread_cond_broadcast() or 35 // pthread_cond_signal(). 36 37 38 #include <condition_variable> 39 #include <atomic> 40 #include <mutex> 41 #include <thread> 42 #include <cassert> 43 44 #include "make_test_thread.h" 45 #include "test_macros.h" 46 47 48 std::condition_variable cv; 49 std::mutex mut; 50 51 std::atomic_int test1(0); 52 std::atomic_int test2(0); 53 std::atomic_int ready(2); 54 std::atomic_int which(0); 55 f1()56void f1() 57 { 58 std::unique_lock<std::mutex> lk(mut); 59 assert(test1 == 0); 60 --ready; 61 while (test1 == 0) 62 cv.wait(lk); 63 which = 1; 64 assert(test1 == 1); 65 test1 = 2; 66 } 67 f2()68void f2() 69 { 70 std::unique_lock<std::mutex> lk(mut); 71 assert(test2 == 0); 72 --ready; 73 while (test2 == 0) 74 cv.wait(lk); 75 which = 2; 76 assert(test2 == 1); 77 test2 = 2; 78 } 79 main(int,char **)80int main(int, char**) 81 { 82 std::thread t1 = support::make_test_thread(f1); 83 std::thread t2 = support::make_test_thread(f2); 84 { 85 while (ready > 0) 86 std::this_thread::yield(); 87 // At this point: 88 // 1) Both f1 and f2 have entered their condition variable wait. 89 // 2) Either f1 or f2 has the mutex locked and is about to wait. 90 std::unique_lock<std::mutex> lk(mut); 91 test1 = 1; 92 test2 = 1; 93 ready = 1; 94 cv.notify_one(); 95 } 96 { 97 while (which == 0) 98 std::this_thread::yield(); 99 std::unique_lock<std::mutex> lk(mut); 100 if (test1 == 2) { 101 assert(test2 == 1); 102 t1.join(); 103 test1 = 0; 104 } else { 105 assert(test1 == 1); 106 assert(test2 == 2); 107 t2.join(); 108 test2 = 0; 109 } 110 which = 0; 111 cv.notify_one(); 112 } 113 { 114 while (which == 0) 115 std::this_thread::yield(); 116 std::unique_lock<std::mutex> lk(mut); 117 if (test1 == 2) { 118 assert(test2 == 0); 119 t1.join(); 120 test1 = 0; 121 } else { 122 assert(test1 == 0); 123 assert(test2 == 2); 124 t2.join(); 125 test2 = 0; 126 } 127 } 128 129 return 0; 130 } 131