114 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-threads, c++0310 11// <condition_variable>12 13// class condition_variable;14 15// template <class Predicate>16// void wait(unique_lock<mutex>& lock, Predicate pred);17 18#include <condition_variable>19#include <atomic>20#include <cassert>21#include <mutex>22#include <thread>23 24#include "make_test_thread.h"25#include "test_macros.h"26 27int main(int, char**) {28 // Test unblocking via a call to notify_one() in another thread.29 //30 // To test this, we try to minimize the likelihood that we got awoken by a31 // spurious wakeup by updating the likely_spurious flag only immediately32 // before we perform the notification.33 {34 std::atomic<bool> ready(false);35 std::atomic<bool> likely_spurious(true);36 std::condition_variable cv;37 std::mutex mutex;38 39 std::thread t1 = support::make_test_thread([&] {40 std::unique_lock<std::mutex> lock(mutex);41 ready = true;42 cv.wait(lock, [&] { return !likely_spurious; });43 });44 45 std::thread t2 = support::make_test_thread([&] {46 while (!ready) {47 // spin48 }49 50 // Acquire the same mutex as t1. This ensures that the condition variable has started51 // waiting (and hence released that mutex).52 std::unique_lock<std::mutex> lock(mutex);53 54 likely_spurious = false;55 lock.unlock();56 cv.notify_one();57 });58 59 t2.join();60 t1.join();61 }62 63 // Test unblocking via a spurious wakeup.64 //65 // To test this, we basically never wake up the condition variable. This way, we66 // are hoping to get out of the wait via a spurious wakeup.67 //68 // However, since spurious wakeups are not required to even happen, this test is69 // only trying to trigger that code path, but not actually asserting that it is70 // taken. In particular, we do need to eventually ensure we get out of the wait71 // by standard means, so we actually wake up the thread at the end.72 {73 std::atomic<bool> ready(false);74 std::atomic<bool> awoken(false);75 std::condition_variable cv;76 std::mutex mutex;77 78 std::thread t1 = support::make_test_thread([&] {79 std::unique_lock<std::mutex> lock(mutex);80 ready = true;81 cv.wait(lock, [&] { return true; });82 awoken = true;83 });84 85 std::thread t2 = support::make_test_thread([&] {86 while (!ready) {87 // spin88 }89 90 // Acquire the same mutex as t1. This ensures that the condition variable has started91 // waiting (and hence released that mutex).92 std::unique_lock<std::mutex> lock(mutex);93 lock.unlock();94 95 // Give some time for t1 to be awoken spuriously so that code path is used.96 std::this_thread::sleep_for(std::chrono::seconds(1));97 98 // We would want to assert that the thread has been awoken after this time,99 // however nothing guarantees us that it ever gets spuriously awoken, so100 // we can't really check anything. This is still left here as documentation.101 bool woke = awoken.load();102 assert(woke || !woke);103 104 // Whatever happened, actually awaken the condition variable to ensure the test finishes.105 cv.notify_one();106 });107 108 t2.join();109 t1.join();110 }111 112 return 0;113}114