Event.h 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. // Copyright 2014 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. // Multithreaded event class. This allows waiting in a thread for an event to
  4. // be triggered in another thread. While waiting, the CPU will be available for
  5. // other tasks.
  6. // * Set(): triggers the event and wakes up the waiting thread.
  7. // * Wait(): waits for the event to be triggered.
  8. // * Reset(): tries to reset the event before the waiting thread sees it was
  9. // triggered. Usually a bad idea.
  10. #pragma once
  11. #ifdef _WIN32
  12. #include <concrt.h>
  13. #endif
  14. #include <chrono>
  15. #include <condition_variable>
  16. #include <mutex>
  17. #include "Common/Flag.h"
  18. namespace Common
  19. {
  20. class Event final
  21. {
  22. public:
  23. void Set()
  24. {
  25. if (m_flag.TestAndSet())
  26. {
  27. // Lock and immediately unlock m_mutex.
  28. {
  29. // Holding the lock at any time between the change of our flag and notify call
  30. // is sufficient to prevent a race where both of these actions
  31. // happen between the other thread's predicate test and wait call
  32. // which would cause wait to block until the next spurious wakeup or timeout.
  33. // Unlocking before notification is a micro-optimization to prevent
  34. // the notified thread from immediately blocking on the mutex.
  35. std::lock_guard<std::mutex> lk(m_mutex);
  36. }
  37. m_condvar.notify_one();
  38. }
  39. }
  40. void Wait()
  41. {
  42. if (m_flag.TestAndClear())
  43. return;
  44. std::unique_lock<std::mutex> lk(m_mutex);
  45. m_condvar.wait(lk, [&] { return m_flag.TestAndClear(); });
  46. }
  47. template <class Rep, class Period>
  48. bool WaitFor(const std::chrono::duration<Rep, Period>& rel_time)
  49. {
  50. if (m_flag.TestAndClear())
  51. return true;
  52. std::unique_lock<std::mutex> lk(m_mutex);
  53. bool signaled = m_condvar.wait_for(lk, rel_time, [&] { return m_flag.TestAndClear(); });
  54. return signaled;
  55. }
  56. void Reset()
  57. {
  58. // no other action required, since wait loops on
  59. // the predicate and any lingering signal will get
  60. // cleared on the first iteration
  61. m_flag.Clear();
  62. }
  63. private:
  64. Flag m_flag;
  65. std::condition_variable m_condvar;
  66. std::mutex m_mutex;
  67. };
  68. } // namespace Common