BsTaskScheduler.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. //__________________________ Banshee Project - A modern game development toolkit _________________________________//
  2. //_____________________________________ www.banshee-project.com __________________________________________________//
  3. //________________________ Copyright (c) 2014 Marko Pintera. All rights reserved. ________________________________//
  4. #pragma once
  5. #include "BsPrerequisitesUtil.h"
  6. #include "BsModule.h"
  7. #include "BsThreadPool.h"
  8. namespace BansheeEngine
  9. {
  10. /**
  11. * @brief Task priority. Tasks with higher priority will get executed sooner.
  12. */
  13. enum class TaskPriority
  14. {
  15. VeryLow = 98,
  16. Low = 99,
  17. Normal = 100,
  18. High = 101,
  19. VeryHigh = 102
  20. };
  21. /**
  22. * @brief Represents a single task that may be queued in the TaskScheduler.
  23. *
  24. * @note Thread safe.
  25. */
  26. class BS_UTILITY_EXPORT Task
  27. {
  28. struct PrivatelyConstruct {};
  29. public:
  30. Task(const PrivatelyConstruct& dummy, const String& name, std::function<void()> taskWorker,
  31. TaskPriority priority, TaskPtr dependency);
  32. /**
  33. * @brief Creates a new task. Task should be provided to TaskScheduler in order for it
  34. * to start.
  35. *
  36. * @param name Name you can use to more easily identify the task.
  37. * @param taskWorker Worker method that does all of the work in the task.
  38. * @param priority (optional) Higher priority means the tasks will be executed sooner.
  39. * @param dependency (optional) Task dependency if one exists. If provided the task will
  40. * not be executed until its dependency is complete.
  41. */
  42. static TaskPtr create(const String& name, std::function<void()> taskWorker, TaskPriority priority = TaskPriority::Normal,
  43. TaskPtr dependency = nullptr);
  44. /**
  45. * @brief Returns true if the task has completed.
  46. */
  47. bool isComplete() const;
  48. /**
  49. * @brief Returns true if the task has been canceled.
  50. */
  51. bool isCanceled() const;
  52. /**
  53. * @brief Blocks the current thread until the task has completed.
  54. *
  55. * @note While waiting adds a new worker thread, so that the blocking threads core can be utilized.
  56. */
  57. void wait();
  58. /**
  59. * @brief Cancels the task and removes it from the TaskSchedulers queue.
  60. */
  61. void cancel();
  62. private:
  63. friend class TaskScheduler;
  64. String mName;
  65. TaskPriority mPriority;
  66. UINT32 mTaskId;
  67. std::function<void()> mTaskWorker;
  68. TaskPtr mTaskDependency;
  69. std::atomic<UINT32> mState; /**< 0 - Inactive, 1 - In progress, 2 - Completed, 3 - Canceled */
  70. TaskScheduler* mParent;
  71. };
  72. /**
  73. * @brief Represents a task scheduler running on multiple threads. You may queue
  74. * tasks on it from any thread and they will be executed in user specified order
  75. * on any available thread.
  76. *
  77. * @note Thread safe.
  78. *
  79. * This type of task scheduler uses a global queue and is best used for coarse granularity of tasks.
  80. * (Number of tasks in the order of hundreds. Higher number of tasks might require different queuing and
  81. * locking mechanism, potentially at the cost of flexibility.)
  82. *
  83. * By default the task scheduler will create as many threads as there are physical CPU cores. You may add or remove
  84. * threads using addWorker/removeWorker methods.
  85. */
  86. class BS_UTILITY_EXPORT TaskScheduler : public Module<TaskScheduler>
  87. {
  88. public:
  89. TaskScheduler();
  90. ~TaskScheduler();
  91. /**
  92. * @brief Queues a new task.
  93. */
  94. void addTask(const TaskPtr& task);
  95. /**
  96. * @brief Adds a new worker thread which will be used for executing queued tasks.
  97. */
  98. void addWorker();
  99. /**
  100. * @brief Removes a worker thread (as soon as its current task is finished).
  101. */
  102. void removeWorker();
  103. protected:
  104. friend class Task;
  105. /**
  106. * @brief Main task scheduler method that dispatches tasks to other threads.
  107. */
  108. void runMain();
  109. /**
  110. * @brief Worker method that runs a single task.
  111. */
  112. void runTask(TaskPtr task);
  113. /**
  114. * @brief Blocks the calling thread until the specified task has completed.
  115. */
  116. void waitUntilComplete(const Task* task);
  117. /**
  118. * @brief Method used for sorting tasks.
  119. */
  120. static bool taskCompare(const TaskPtr& lhs, const TaskPtr& rhs);
  121. HThread mTaskSchedulerThread;
  122. Set<TaskPtr, std::function<bool(const TaskPtr&, const TaskPtr&)>> mTaskQueue;
  123. Vector<TaskPtr> mActiveTasks;
  124. UINT32 mNumActiveTasks;
  125. UINT32 mMaxActiveTasks;
  126. UINT32 mNextTaskId;
  127. bool mShutdown;
  128. BS_MUTEX(mReadyMutex);
  129. BS_MUTEX(mCompleteMutex);
  130. BS_MUTEX(mActiveTaskMutex);
  131. BS_THREAD_SYNCHRONISER(mTaskReadyCond);
  132. BS_THREAD_SYNCHRONISER(mTaskCompleteCond);
  133. };
  134. }