暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ScopedAcquire.h 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #pragma once
  2. #include "Time.h"
  3. namespace baselib
  4. {
  5. BASELIB_CPP_INTERFACE
  6. {
  7. // Object that will on destruction call Release() on the sync primitive referenced by syncPrimitivePtr.
  8. // Initializing ScopedRelease with a nullptr signals Acquire failed.
  9. //
  10. template<typename T>
  11. class ScopedRelease
  12. {
  13. public:
  14. FORCE_INLINE ScopedRelease(T* syncPrimitivePtr) : m_SyncPrimitivePtr(syncPrimitivePtr) {}
  15. FORCE_INLINE ~ScopedRelease() { if (m_SyncPrimitivePtr) m_SyncPrimitivePtr->Release(); }
  16. // non-copyable
  17. ScopedRelease(const ScopedRelease& other) = delete;
  18. ScopedRelease& operator=(const ScopedRelease& other) = delete;
  19. // move-constructable, but not assignable as it doesn't make much sense to swap locks.
  20. ScopedRelease(ScopedRelease&& other)
  21. {
  22. this->m_SyncPrimitivePtr = other.m_SyncPrimitivePtr;
  23. other.m_SyncPrimitivePtr = nullptr;
  24. }
  25. ScopedRelease& operator=(ScopedRelease&& other) = delete;
  26. // Returns false if either this object was created from a failed TryAcquireScoped/TryTimedAcquireScoped or ownership was moved.
  27. bool WasSuccessfullyAcquired() const { return m_SyncPrimitivePtr != nullptr; }
  28. // Returns false if either this object was created from a failed TryAcquireScoped/TryTimedAcquireScoped or ownership was moved.
  29. operator bool() const { return WasSuccessfullyAcquired(); }
  30. private:
  31. T* m_SyncPrimitivePtr;
  32. };
  33. // Call Acquire and return an object that calls Release on its destruction.
  34. //
  35. // Example usage:
  36. // {
  37. // auto scope = AcquireScoped(lock);
  38. // enteredCriticalSection++;
  39. // }
  40. template<class T>
  41. COMPILER_WARN_UNUSED_RESULT
  42. FORCE_INLINE ScopedRelease<T> AcquireScoped(T& synchronizationObject, const uint32_t maxSpinCount = 0)
  43. {
  44. synchronizationObject.Acquire(maxSpinCount);
  45. return ScopedRelease<T>(&synchronizationObject);
  46. }
  47. // Call TryAcquire and return an object that calls Release on its destruction.
  48. // The returned object will be flagged unsuccessful and not call Release if TryAcquire failed.
  49. //
  50. // Example usage:
  51. // {
  52. // auto result = TryAcquireScoped(lock);
  53. // if (result)
  54. // {
  55. // enteredCriticalSection++;
  56. // ]
  57. // }
  58. template<class T>
  59. COMPILER_WARN_UNUSED_RESULT
  60. FORCE_INLINE ScopedRelease<T> TryAcquireScoped(T& synchronizationObject, const uint32_t maxSpinCount = 0)
  61. {
  62. return ScopedRelease<T>(synchronizationObject.TryAcquire(maxSpinCount) ? &synchronizationObject : nullptr);
  63. }
  64. // Call TryTimedAcquire and return an object that calls Release on its destruction.
  65. // The returned object will be flagged unsuccessful and not call Release if TryTimedAcquire failed.
  66. //
  67. // Example usage:
  68. // {
  69. // auto result = TryTimedAcquireScoped(lock, std::chrono::minutes(1));
  70. // if (result)
  71. // {
  72. // enteredCriticalSection++;
  73. // }
  74. // assert(result);
  75. // }
  76. template<class T>
  77. COMPILER_WARN_UNUSED_RESULT
  78. FORCE_INLINE ScopedRelease<T> TryTimedAcquireScoped(T& synchronizationObject, const timeout_ms timeoutInMilliseconds, const uint32_t maxSpinCount = 0)
  79. {
  80. return ScopedRelease<T>(synchronizationObject.TryTimedAcquire(timeoutInMilliseconds, maxSpinCount) ? &synchronizationObject : nullptr);
  81. }
  82. // Call Acquire, invoke user defined function then call Release.
  83. //
  84. // Example usage:
  85. // AcquireScoped(lock, [] {
  86. // enteredCriticalSection++;
  87. // });
  88. template<class T, class FunctionType>
  89. FORCE_INLINE void AcquireScoped(T& synchronizationObject, const FunctionType& func, const uint32_t maxSpinCount = 0)
  90. {
  91. const auto scopedRelease = baselib::AcquireScoped(synchronizationObject, maxSpinCount);
  92. func();
  93. }
  94. // Call TryAcquire, if successful invoke user defined function then call Release.
  95. //
  96. // Example usage:
  97. // bool lockAcquired = TryAcquireScoped(lock, [] {
  98. // enteredCriticalSection++;
  99. // });
  100. //
  101. // Return: true if acquired and user function was invoked.
  102. template<class T, class FunctionType>
  103. FORCE_INLINE bool TryAcquireScoped(T& synchronizationObject, const FunctionType& func, const uint32_t maxSpinCount = 0)
  104. {
  105. const auto scopedRelease = baselib::TryAcquireScoped(synchronizationObject, maxSpinCount);
  106. if (scopedRelease)
  107. {
  108. func();
  109. return true;
  110. }
  111. return false;
  112. }
  113. // Call TryTimedAcquire, if successful invoke user defined function then call Release.
  114. //
  115. // Example usage:
  116. // bool lockAcquired = lock.TryTimedAcquireScoped(std::chrono::minutes(1), [] {
  117. // enteredCriticalSection++;
  118. // });
  119. // assert(lockAcquired);
  120. //
  121. // Return: true if acquired and user function was invoked.
  122. template<class T, class FunctionType>
  123. FORCE_INLINE bool TryTimedAcquireScoped(T& synchronizationObject, const timeout_ms timeoutInMilliseconds, const FunctionType& func, const uint32_t maxSpinCount = 0)
  124. {
  125. const auto scopedRelease = baselib::TryTimedAcquireScoped(synchronizationObject, timeoutInMilliseconds, maxSpinCount);
  126. if (scopedRelease)
  127. {
  128. func();
  129. return true;
  130. }
  131. return false;
  132. }
  133. }
  134. }