2
0

BsAsyncOp.h 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #pragma once
  4. #include "Prerequisites/BsPrerequisitesUtil.h"
  5. #include "Error/BsException.h"
  6. #include "Utility/BsAny.h"
  7. namespace bs
  8. {
  9. /** @addtogroup Internal-Utility
  10. * @{
  11. */
  12. /** @addtogroup Threading-Internal
  13. * @{
  14. */
  15. /** Thread synchronization primitives used by AsyncOps and their callers. */
  16. class BS_UTILITY_EXPORT AsyncOpSyncData
  17. {
  18. public:
  19. Mutex mMutex;
  20. Signal mCondition;
  21. };
  22. /**
  23. * Flag used for creating async operations signaling that we want to create an empty AsyncOp with no internal
  24. * memory storage.
  25. */
  26. struct BS_UTILITY_EXPORT AsyncOpEmpty {};
  27. /** @} */
  28. /** @} */
  29. /** @addtogroup Threading
  30. * @{
  31. */
  32. /**
  33. * Object you may use to check on the results of an asynchronous operation. Contains uninitialized data until
  34. * hasCompleted() returns true.
  35. *
  36. * @note
  37. * You are allowed (and meant to) to copy this by value.
  38. * @note
  39. * You'll notice mIsCompleted isn't synchronized. This is because we're okay if mIsCompleted reports true a few cycles
  40. * too late, which is not relevant for practical use. And in cases where you need to ensure operation has completed
  41. * you will usually use some kind of synchronization primitive that includes a memory barrier anyway.
  42. */
  43. class BS_UTILITY_EXPORT AsyncOp
  44. {
  45. private:
  46. struct AsyncOpData
  47. {
  48. AsyncOpData()
  49. :mIsCompleted(false)
  50. { }
  51. Any mReturnValue;
  52. volatile std::atomic<bool> mIsCompleted;
  53. };
  54. public:
  55. AsyncOp()
  56. :mData(bs_shared_ptr_new<AsyncOpData>())
  57. { }
  58. AsyncOp(AsyncOpEmpty empty)
  59. { }
  60. AsyncOp(const SPtr<AsyncOpSyncData>& syncData)
  61. :mData(bs_shared_ptr_new<AsyncOpData>()), mSyncData(syncData)
  62. { }
  63. AsyncOp(AsyncOpEmpty empty, const SPtr<AsyncOpSyncData>& syncData)
  64. :mSyncData(syncData)
  65. { }
  66. /** Returns true if the async operation has completed. */
  67. bool hasCompleted() const;
  68. /**
  69. * Blocks the caller thread until the AsyncOp completes.
  70. *
  71. * @note
  72. * Do not call this on the thread that is completing the async op, as it will cause a deadlock. Make sure the
  73. * command you are waiting for is actually queued for execution because a deadlock will occur otherwise.
  74. */
  75. void blockUntilComplete() const;
  76. /** Retrieves the value returned by the async operation. Only valid if hasCompleted() returns true. */
  77. template <typename T>
  78. T getReturnValue() const
  79. {
  80. #if BS_DEBUG_MODE
  81. if(!hasCompleted())
  82. BS_EXCEPT(InternalErrorException, "Trying to get AsyncOp return value but the operation hasn't completed.");
  83. #endif
  84. // Be careful if cast throws an exception. It doesn't support casting of polymorphic types. Provided and returned
  85. // types must be EXACT. (You'll have to cast the data yourself when completing the operation)
  86. return any_cast<T>(mData->mReturnValue);
  87. }
  88. /**
  89. * Retrieves the value returned by the async operation as a generic type. Only valid if hasCompleted() returns
  90. * true.
  91. */
  92. Any getGenericReturnValue() const { return mData->mReturnValue; }
  93. public: // ***** INTERNAL ******
  94. /** @name Internal
  95. * @{
  96. */
  97. /** Mark the async operation as completed. */
  98. void _completeOperation(Any returnValue);
  99. /** Mark the async operation as completed, without setting a return value. */
  100. void _completeOperation();
  101. /** @} */
  102. private:
  103. SPtr<AsyncOpData> mData;
  104. SPtr<AsyncOpSyncData> mSyncData;
  105. };
  106. /** @} */
  107. }