BsAsyncOp.h 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. #pragma once
  2. #include "BsPrerequisitesUtil.h"
  3. #include "BsException.h"
  4. #include "BsAny.h"
  5. namespace BansheeEngine
  6. {
  7. /**
  8. * @brief Object you may use to check on the results of an asynchronous operation.
  9. * Contains uninitialized data until "hasCompleted" returns true.
  10. *
  11. * @note You are allowed (and meant to) to copy this by value.
  12. *
  13. * You'll notice mIsCompleted isn't synchronized. This is because we're okay if
  14. * mIsCompleted reports true a few cycles too late, which is not relevant for practical use.
  15. * And in cases where you need to ensure operation has completed you will usually use some kind
  16. * of synchronization primitive that includes a memory barrier anyway.
  17. */
  18. class BS_UTILITY_EXPORT AsyncOp
  19. {
  20. private:
  21. struct AsyncOpData
  22. {
  23. AsyncOpData()
  24. :mIsCompleted(false)
  25. { }
  26. Any mReturnValue;
  27. volatile bool mIsCompleted;
  28. };
  29. public:
  30. AsyncOp()
  31. :mData(bs_shared_ptr<AsyncOpData, ScratchAlloc>())
  32. {
  33. #if BS_ARCH_TYPE != BS_ARCHITECTURE_x86_32 && BS_ARCH_TYPE != BS_ARCHITECTURE_x86_64
  34. // On some architectures it is not guaranteed that stores are executed in order, which means
  35. // return value could be stored after mIsCompleted is set
  36. static_assert(false, "You will likely need to add a memory barrier for mIsCompleted on architectures other than x86.");
  37. #endif
  38. }
  39. /**
  40. * @brief True if the async operation has completed.
  41. */
  42. bool hasCompleted() const { return mData->mIsCompleted; }
  43. /**
  44. * @brief Internal method. Mark the async operation as completed.
  45. */
  46. void _completeOperation(Any returnValue);
  47. /**
  48. * @brief Internal method. Mark the async operation as completed, without setting a return value.
  49. */
  50. void _completeOperation();
  51. /**
  52. * @brief Retrieves the value returned by the async operation. Only valid
  53. * if "hasCompleted" returns true.
  54. */
  55. template <typename T>
  56. T getReturnValue() const
  57. {
  58. #if BS_DEBUG_MODE
  59. if(!hasCompleted())
  60. BS_EXCEPT(InternalErrorException, "Trying to get AsyncOp return value but the operation hasn't completed.");
  61. #endif
  62. // Be careful if cast throws an exception. It doesn't support casting of polymorphic types. Provided and returned
  63. // types must be EXACT. (You'll have to cast the data yourself when completing the operation)
  64. return any_cast<T>(mData->mReturnValue);
  65. }
  66. private:
  67. std::shared_ptr<AsyncOpData> mData;
  68. };
  69. }