ConditionVariable.h 4.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. #pragma once
  2. #include "Time.h"
  3. #include "Lock.h"
  4. #include <cstdint>
  5. #if PLATFORM_FUTEX_NATIVE_SUPPORT
  6. #include "Internal/ConditionVariableData_FutexBased.inl.h"
  7. #else
  8. #include "Internal/ConditionVariableData_SemaphoreBased.inl.h"
  9. #endif
  10. namespace baselib
  11. {
  12. BASELIB_CPP_INTERFACE
  13. {
  14. // Conceptually a condition variable is a queue of threads, associated with a monitor, on which a thread may wait for some condition to become true.
  15. //
  16. // Thus each condition variable c is associated with an assertion Pc. While a thread is waiting on a condition variable, that thread is not considered
  17. // to occupy the monitor, and so other threads may enter the monitor to change the monitor's state. In most types of monitors, these other threads may
  18. // signal the condition variable c to indicate that assertion Pc is true in the current state.
  19. //
  20. // "Monitor (synchronization)", Wikipedia: The Free Encyclopedia
  21. // https://en.wikipedia.org/w/index.php?title=Monitor_(synchronization)&oldid=914426020#Condition_variables_2
  22. //
  23. // For optimal performance, baselib::ConditionVariable should be stored at a cache aligned memory location.
  24. class ConditionVariable
  25. {
  26. public:
  27. // non-copyable
  28. ConditionVariable(const ConditionVariable& other) = delete;
  29. ConditionVariable& operator=(const ConditionVariable& other) = delete;
  30. // non-movable (strictly speaking not needed but listed to signal intent)
  31. ConditionVariable(ConditionVariable&& other) = delete;
  32. ConditionVariable& operator=(ConditionVariable&& other) = delete;
  33. // Creates a condition variable synchronization primitive.
  34. ConditionVariable(Lock& lock) : m_Lock(lock)
  35. {}
  36. // Reclaim resources and memory held by the condition variable.
  37. //
  38. // If threads are waiting on the condition variable, destructor will trigger an assert and may cause process abort.
  39. ~ConditionVariable()
  40. {
  41. BaselibAssert(!m_Data.HasWaiters(), "Destruction is not allowed when there are still threads waiting on the condition variable.");
  42. NotifyAll();
  43. }
  44. // Wait for the condition variable to become available.
  45. //
  46. // The lock must have been previously acquired.
  47. // For the duration of the wait the lock is released and then re-acquired upon exit.
  48. // This function is guaranteed to emit an acquire barrier.
  49. inline void Wait();
  50. // Wait for the condition variable to become available.
  51. //
  52. // The lock must have been previously acquired.
  53. // For the duration of the wait the lock is released and then re-acquired upon exit.
  54. // This function is guaranteed to emit an acquire barrier.
  55. //
  56. // TimedWait with a zero timeout is guaranteed to be a user space operation.
  57. //
  58. // \param timeoutInMilliseconds Time to wait for condition variable to become available.
  59. // \returns true if the condition variable is available, false if timeout was reached.
  60. inline bool TimedWait(const timeout_ms timeoutInMilliseconds);
  61. // Post `count` number of tokens and wake up thread(s) waiting for the condition variable to become available.
  62. //
  63. // This function does *not* guarantee fairness so it is possible not all threads waiting are woken up if multiple tokens are consumed by one thread.
  64. // This function is guaranteed to emit a release barrier.
  65. //
  66. // \param count At most, `count` waiting threads will be notified, but never more than there are currently waiting.
  67. inline void Notify(uint16_t count);
  68. // Post maximum number of tokens and wake up thread(s) waiting for the condition variable to become available.
  69. //
  70. // This function does *not* guarantee fairness so it is possible not all threads waiting are woken up if multiple tokens are consumed by one thread.
  71. // This function is guaranteed to emit a release barrier.
  72. inline void NotifyAll()
  73. {
  74. Notify(std::numeric_limits<uint16_t>::max());
  75. }
  76. private:
  77. Lock& m_Lock;
  78. detail::ConditionVariableData m_Data;
  79. };
  80. }
  81. }
  82. #if PLATFORM_FUTEX_NATIVE_SUPPORT
  83. #include "Internal/ConditionVariable_FutexBased.inl.h"
  84. #else
  85. #include "Internal/ConditionVariable_SemaphoreBased.inl.h"
  86. #endif