WwiseExecutionQueue.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*******************************************************************************
  2. The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
  3. Technology released in source code form as part of the game integration package.
  4. The content of this file may not be used without valid licenses to the
  5. AUDIOKINETIC Wwise Technology.
  6. Note that the use of the game engine is subject to the Unreal(R) Engine End User
  7. License Agreement at https://www.unrealengine.com/en-US/eula/unreal
  8. License Usage
  9. Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
  10. this file in accordance with the end user license agreement provided with the
  11. software or, alternatively, in accordance with the terms contained
  12. in a written agreement between you and Audiokinetic Inc.
  13. Copyright (c) 2023 Audiokinetic Inc.
  14. *******************************************************************************/
  15. #pragma once
  16. #include "Async/TaskGraphInterfaces.h"
  17. #include "Containers/Queue.h"
  18. #include "Misc/DateTime.h"
  19. #include "Misc/QueuedThreadPool.h"
  20. /**
  21. * @brief Asynchronous sequential execution queue.
  22. *
  23. * The goal of the Execution Queue is to call asynchronous operations sequentially. In effect,
  24. * this creates the equivalent of a GCD's Dispatch Queue, where operations are known to be executed
  25. * one after the other, but asynchronously.
  26. */
  27. struct WWISECONCURRENCY_API FWwiseExecutionQueue
  28. {
  29. const ENamedThreads::Type NamedThread;
  30. FQueuedThreadPool * const ThreadPool;
  31. const bool bOwnedPool;
  32. using FBasicFunction = TUniqueFunction<void()>;
  33. /**
  34. * @brief Starts a new Execution Queue running in a particular Named Thread
  35. * @param InNamedThread The Named Thread that will run the Execution Queue
  36. */
  37. FWwiseExecutionQueue(ENamedThreads::Type InNamedThread);
  38. /**
  39. * @brief Starts a new Execution Queue running in a particular Thread Pool
  40. * @param InThreadPool The Thread Pool that will run the Execution Queue. Using nullptr will run it in the
  41. * Wwise Execution Queue's default thread pool.
  42. */
  43. FWwiseExecutionQueue(FQueuedThreadPool* InThreadPool = nullptr);
  44. /**
  45. * @brief Starts a new Execution Queue running in a new, owned Thread Pool (with 1 thread) exclusive to this Execution Queue.
  46. * @param InThreadName Thread Name
  47. * @param InThreadPriority Thread Priority of the new Thread Pool
  48. * @param InStackSize Stack size for new Thread Pool
  49. */
  50. FWwiseExecutionQueue(const TCHAR* InThreadName, EThreadPriority InThreadPriority = EThreadPriority::TPri_Normal, int32 InStackSize = 128 * 1024);
  51. /**
  52. * @brief Destructor for Execution Queue.
  53. *
  54. * This will lock the calling thread until the Execution Queue is actually closed.
  55. *
  56. * If the Execution Queue can be deleted while executing its own Async operation, you need to call CloseAndDelete() instead
  57. * of deleting the Execution Queue yourself.
  58. */
  59. ~FWwiseExecutionQueue();
  60. /**
  61. * @brief Calls a function asynchronously in the Execution Queue.
  62. * @param InFunction The function to be called.
  63. *
  64. * Async usually calls the passed function asynchronously. However, in deletion instances or exiting instances, this
  65. * will be called synchronously. If you absolutely need this call to be done asynchronously (it might not be called),
  66. * you should call AsyncAlways instead.
  67. */
  68. void Async(FBasicFunction&& InFunction);
  69. /**
  70. * @brief Calls a function asynchronously in the Execution Queue. If no Execution Queue is available, it will be called
  71. * on any Task Graph thread.
  72. * @param InFunction The function to be called.
  73. *
  74. * Execute the function asynchronously, or on the Task Graph, but never synchronously.
  75. */
  76. void AsyncAlways(FBasicFunction&& InFunction);
  77. /**
  78. * @brief Calls a function asynchronously in the Execution Queue, and then wait for it to be called.
  79. * @param InFunction The function to be called.
  80. */
  81. void AsyncWait(FBasicFunction&& InFunction);
  82. /**
  83. * @brief Permanently closes the Execution Queue, ensuring every Async operations are done processing before closing.
  84. *
  85. * This gets called by the destructor. This will lock the calling thread until the Execution Queue is actually closed.
  86. */
  87. void Close();
  88. /**
  89. * @brief Permanently closes the Execution Queue once it's done processing asynchronously. Then, deletes the Execution Queue pointer.
  90. *
  91. * This is the way to destroy an Execution Queue whose destruction can be achieved through one of its own function. For example,
  92. * an object that async a structure cleanup, and then removes itself once it's possible to delete it.
  93. */
  94. void CloseAndDelete();
  95. bool IsBeingClosed() const;
  96. bool IsClosed() const;
  97. static FQueuedThreadPool* GetDefaultThreadPool();
  98. private:
  99. class ExecutionQueuePoolTask;
  100. enum class EWorkerState
  101. {
  102. Stopped, ///< Idle
  103. Running, ///< There is a thread owner executing operations
  104. AddOp, ///< While a thread is running, a producer is adding operations
  105. Closing, ///< While a thread is running, the last producer is asking to permanently close the Execution Queue
  106. Closed ///< Execution Queue is permanently closed. It can be deleted.
  107. };
  108. TAtomic<EWorkerState> WorkerState{ EWorkerState::Stopped };
  109. bool bDeleteOnceClosed{ false };
  110. using FOpQueue = TQueue<FBasicFunction, EQueueMode::Mpsc>;
  111. FOpQueue OpQueue;
  112. void StartWorkerIfNeeded();
  113. void Work();
  114. bool StopWorkerIfDone();
  115. void ProcessWork();
  116. bool TrySetStoppedWorkerToRunning();
  117. bool TrySetRunningWorkerToStopped();
  118. bool TrySetRunningWorkerToAddOp();
  119. bool TrySetAddOpWorkerToRunning();
  120. bool TrySetRunningWorkerToClosing();
  121. bool TrySetClosingWorkerToClosed();
  122. static const TCHAR* StateName(EWorkerState State);
  123. FORCEINLINE bool TryStateUpdate(EWorkerState NeededState, EWorkerState WantedState);
  124. private:
  125. FWwiseExecutionQueue(const FWwiseExecutionQueue& Rhs) = delete;
  126. FWwiseExecutionQueue(FWwiseExecutionQueue&& Rhs) = delete;
  127. FWwiseExecutionQueue& operator=(const FWwiseExecutionQueue& Rhs) = delete;
  128. FWwiseExecutionQueue& operator=(FWwiseExecutionQueue&& Rhs) = delete;
  129. public:
  130. struct WWISECONCURRENCY_API Test
  131. {
  132. #if defined(WITH_LOW_LEVEL_TESTS) && WITH_LOW_LEVEL_TESTS || defined(WITH_AUTOMATION_TESTS) || (WITH_DEV_AUTOMATION_TESTS || WITH_PERF_AUTOMATION_TESTS)
  133. static bool bMockEngineDeletion;
  134. static bool bMockEngineDeleted;
  135. #else
  136. static constexpr const auto bMockEngineDeletion{ false };
  137. static constexpr const auto bMockEngineDeleted{ false };
  138. #endif
  139. };
  140. };