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