Event.h 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // Copyright 2014 Dolphin Emulator Project
  2. // Licensed under GPLv2+
  3. // Refer to the license.txt file included.
  4. // Multithreaded event class. This allows waiting in a thread for an event to
  5. // be triggered in another thread. While waiting, the CPU will be available for
  6. // other tasks.
  7. // * Set(): triggers the event and wakes up the waiting thread.
  8. // * Wait(): waits for the event to be triggered.
  9. // * Reset(): tries to reset the event before the waiting thread sees it was
  10. // triggered. Usually a bad idea.
  11. #pragma once
  12. #ifdef _WIN32
  13. #include <concrt.h>
  14. #endif
  15. #include <chrono>
  16. #include <condition_variable>
  17. #include <mutex>
  18. #include "Common/Flag.h"
  19. namespace Common {
  20. // Windows uses a specific implementation because std::condition_variable has
  21. // terrible performance for this kind of workload with MSVC++ 2013.
  22. #ifndef _WIN32
  23. class Event final
  24. {
  25. public:
  26. void Set()
  27. {
  28. if (m_flag.TestAndSet())
  29. {
  30. std::lock_guard<std::mutex> lk(m_mutex);
  31. m_condvar.notify_one();
  32. }
  33. }
  34. void Wait()
  35. {
  36. if (m_flag.TestAndClear())
  37. return;
  38. std::unique_lock<std::mutex> lk(m_mutex);
  39. m_condvar.wait(lk, [&]{ return m_flag.IsSet(); });
  40. m_flag.Clear();
  41. }
  42. template<class Rep, class Period>
  43. bool WaitFor(const std::chrono::duration<Rep, Period>& rel_time)
  44. {
  45. if (m_flag.TestAndClear())
  46. return true;
  47. std::unique_lock<std::mutex> lk(m_mutex);
  48. bool signaled = m_condvar.wait_for(lk, rel_time,
  49. [&]{ return m_flag.IsSet(); });
  50. m_flag.Clear();
  51. return signaled;
  52. }
  53. void Reset()
  54. {
  55. // no other action required, since wait loops on
  56. // the predicate and any lingering signal will get
  57. // cleared on the first iteration
  58. m_flag.Clear();
  59. }
  60. private:
  61. Flag m_flag;
  62. std::condition_variable m_condvar;
  63. std::mutex m_mutex;
  64. };
  65. #else
  66. class Event final
  67. {
  68. public:
  69. void Set()
  70. {
  71. m_event.set();
  72. }
  73. void Wait()
  74. {
  75. m_event.wait();
  76. m_event.reset();
  77. }
  78. template<class Rep, class Period>
  79. bool WaitFor(const std::chrono::duration<Rep, Period>& rel_time)
  80. {
  81. bool signaled = m_event.wait(
  82. (u32)std::chrono::duration_cast<std::chrono::milliseconds>(rel_time).count()
  83. ) == 0;
  84. m_event.reset();
  85. return signaled;
  86. }
  87. void Reset()
  88. {
  89. m_event.reset();
  90. }
  91. private:
  92. concurrency::event m_event;
  93. };
  94. #endif
  95. } // namespace Common