brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.4 KiB · 6a054f7 Raw
110 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 Rep, class Period>16//     cv_status17//     wait_for(unique_lock<mutex>& lock,18//              const chrono::duration<Rep, Period>& rel_time);19 20#include <condition_variable>21#include <atomic>22#include <cassert>23#include <chrono>24#include <mutex>25#include <thread>26 27#include "make_test_thread.h"28#include "test_macros.h"29 30template <class Function>31std::chrono::microseconds measure(Function f) {32  std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();33  f();34  std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();35  return std::chrono::duration_cast<std::chrono::microseconds>(end - start);36}37 38int main(int, char**) {39  // Test unblocking via a call to notify_one() in another thread.40  //41  // To test this, we set a very long timeout in wait_for() and we wait42  // again in case we get awoken spuriously. Note that it can actually43  // happen that we get awoken spuriously and fail to recognize it44  // (making this test useless), but the likelihood should be small.45  {46    std::atomic<bool> ready(false);47    std::atomic<bool> likely_spurious(true);48    auto timeout = std::chrono::seconds(3600);49    std::condition_variable cv;50    std::mutex mutex;51 52    std::thread t1 = support::make_test_thread([&] {53      std::unique_lock<std::mutex> lock(mutex);54      auto elapsed = measure([&] {55        ready = true;56        do {57          std::cv_status result = cv.wait_for(lock, timeout);58          assert(result == std::cv_status::no_timeout);59        } while (likely_spurious);60      });61 62      // This can technically fail if we have many spurious awakenings, but in practice the63      // tolerance is so high that it shouldn't be a problem.64      assert(elapsed < timeout);65    });66 67    std::thread t2 = support::make_test_thread([&] {68      while (!ready) {69        // spin70      }71 72      // Acquire the same mutex as t1. This blocks the condition variable inside its wait call73      // so we can notify it while it is waiting.74      std::unique_lock<std::mutex> lock(mutex);75      cv.notify_one();76      likely_spurious = false;77      lock.unlock();78    });79 80    t2.join();81    t1.join();82  }83 84  // Test unblocking via a timeout.85  //86  // To test this, we create a thread that waits on a condition variable87  // with a certain timeout, and we never awaken it. To guard against88  // spurious wakeups, we wait again whenever we are awoken for a reason89  // other than a timeout.90  {91    auto timeout = std::chrono::milliseconds(250);92    std::condition_variable cv;93    std::mutex mutex;94 95    std::thread t1 = support::make_test_thread([&] {96      std::unique_lock<std::mutex> lock(mutex);97      std::cv_status result;98      do {99        auto elapsed = measure([&] { result = cv.wait_for(lock, timeout); });100        if (result == std::cv_status::timeout)101          assert(elapsed >= timeout);102      } while (result != std::cv_status::timeout);103    });104 105    t1.join();106  }107 108  return 0;109}110