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