test_cxx_cond_var.cpp 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. #include <iostream>
  2. #include <thread>
  3. #include <condition_variable>
  4. #include <chrono>
  5. #include <mutex>
  6. #include <atomic>
  7. #include <unistd.h>
  8. #include "freertos/FreeRTOS.h"
  9. #include "unity.h"
  10. #if __GTHREADS && __GTHREADS_CXX0X
  11. static std::condition_variable cv;
  12. static std::mutex cv_m;
  13. static std::atomic<int> i{0};
  14. static void waits(int idx, int timeout_ms)
  15. {
  16. std::unique_lock<std::mutex> lk(cv_m);
  17. auto now = std::chrono::system_clock::now();
  18. if(cv.wait_until(lk, now + std::chrono::milliseconds(timeout_ms), [](){return i == 1;}))
  19. std::cout << "Thread " << idx << " finished waiting. i == " << i << '\n';
  20. else
  21. std::cout << "Thread " << idx << " timed out. i == " << i << '\n';
  22. }
  23. static void signals(int signal_ms)
  24. {
  25. std::this_thread::sleep_for(std::chrono::milliseconds(signal_ms));
  26. std::cout << "Notifying...\n";
  27. cv.notify_all();
  28. std::this_thread::sleep_for(std::chrono::milliseconds(signal_ms));
  29. i = 1;
  30. std::cout << "Notifying again...\n";
  31. cv.notify_all();
  32. }
  33. TEST_CASE("C++ condition_variable", "[std::condition_variable]")
  34. {
  35. i = 0;
  36. std::thread t1(waits, 1, 100), t2(waits, 2, 800), t3(signals, 200);
  37. t1.join();
  38. t2.join();
  39. t3.join();
  40. std::cout << "All threads joined\n";
  41. }
  42. TEST_CASE("cxx: condition_variable can timeout", "[cxx]")
  43. {
  44. std::condition_variable cv;
  45. std::mutex mtx;
  46. std::unique_lock<std::mutex> lck(mtx);
  47. srand(99);
  48. for (int i = 0; i < 10; ++i) {
  49. usleep(rand() % 1000);
  50. auto status = cv.wait_for(lck, std::chrono::milliseconds(200));
  51. TEST_ASSERT_EQUAL(std::cv_status::timeout, status);
  52. }
  53. }
  54. TEST_CASE("cxx: condition_variable timeout never before deadline", "[cxx]")
  55. {
  56. using SysClock = std::chrono::system_clock;
  57. std::mutex mutex;
  58. std::condition_variable cond;
  59. std::unique_lock<std::mutex> lock(mutex);
  60. for (int i = 0; i < 25; ++i) {
  61. auto timeout = std::chrono::milliseconds(portTICK_PERIOD_MS * (i+1));
  62. auto deadline = SysClock::now() + timeout;
  63. auto secs = std::chrono::time_point_cast<std::chrono::seconds>(deadline);
  64. auto nsecs = std::chrono::duration_cast<std::chrono::nanoseconds>
  65. (deadline - secs);
  66. struct timespec ts = {
  67. .tv_sec = static_cast<time_t>(secs.time_since_epoch().count()),
  68. .tv_nsec = static_cast<long>(nsecs.count())};
  69. int rc = ::pthread_cond_timedwait(cond.native_handle(),
  70. lock.mutex()->native_handle(), &ts);
  71. auto status = (rc == ETIMEDOUT) ? std::cv_status::timeout :
  72. std::cv_status::no_timeout;
  73. auto end = SysClock::now();
  74. auto extra = end - deadline;
  75. auto extra_us = extra / std::chrono::microseconds(1);
  76. printf("timeout %lldms Extra time: %lldus, status: %s\n", timeout.count(), extra_us,
  77. (status == std::cv_status::timeout) ? "timeout" : "no timeout");
  78. // The timed wait should always return at least 1us after the timeout deadline
  79. TEST_ASSERT_GREATER_THAN(0, extra_us);
  80. }
  81. }
  82. #endif // __GTHREADS && __GTHREADS_CXX0X