thread_pool.hpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // MIT License
  2. //
  3. // Copyright (c) 2016-2017 Simon Ninon <simon.ninon@gmail.com>
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in all
  13. // copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. // SOFTWARE.
  22. #pragma once
  23. #include <atomic>
  24. #include <condition_variable>
  25. #include <functional>
  26. #include <list>
  27. #include <mutex>
  28. #include <queue>
  29. #include <thread>
  30. #include <vector>
  31. namespace tacopie {
  32. namespace utils {
  33. //!
  34. //! basic thread pool used to push async tasks from the io_service
  35. //!
  36. class thread_pool {
  37. public:
  38. //!
  39. //! ctor
  40. //! created the worker thread that start working immediately
  41. //!
  42. //! \param nb_threads number of threads to start the thread pool
  43. //!
  44. explicit thread_pool(std::size_t nb_threads);
  45. //! dtor
  46. ~thread_pool(void);
  47. //! copy ctor
  48. thread_pool(const thread_pool&) = delete;
  49. //! assignment operator
  50. thread_pool& operator=(const thread_pool&) = delete;
  51. public:
  52. //!
  53. //! task typedef
  54. ///! simply a callable taking no parameter
  55. //!
  56. typedef std::function<void()> task_t;
  57. //!
  58. //! add tasks to thread pool
  59. //! task is enqueued and will be executed whenever all previously executed tasked have been executed (or are currently being executed)
  60. //!
  61. //! \param task task to be executed by the threadpool
  62. //!
  63. void add_task(const task_t& task);
  64. //!
  65. //! same as add_task
  66. //!
  67. //! \param task task to be executed by the threadpool
  68. //! \return current instance
  69. //!
  70. thread_pool& operator<<(const task_t& task);
  71. //!
  72. //! stop the thread pool and wait for workers completion
  73. //! if some tasks are pending, they won't be executed
  74. //!
  75. void stop(void);
  76. public:
  77. //!
  78. //! \return whether the thread_pool is running or not
  79. //!
  80. bool is_running(void) const;
  81. public:
  82. //!
  83. //! reset the number of threads working in the thread pool
  84. //! this can be safely called at runtime and can be useful if you need to adjust the number of workers
  85. //!
  86. //! this function returns immediately, but change might be applied in the background
  87. //! that is, increasing number of threads will spwan new threads directly from this function (but they may take a while to start)
  88. //! moreover, shrinking the number of threads can only be applied in the background to make sure to not stop some threads in the middle of their task
  89. //!
  90. //! changing number of workers do not affect tasks to be executed and tasks currently being executed
  91. //!
  92. //! \param nb_threads number of threads
  93. //!
  94. void set_nb_threads(std::size_t nb_threads);
  95. private:
  96. //!
  97. //! worker main loop
  98. //!
  99. void run(void);
  100. //!
  101. //! retrieve a new task
  102. //! fetch the first element in the queue, or wait if no task are available
  103. //!
  104. //! \return a pair <stopped, task>
  105. //! pair.first indicated whether the thread has been marked for stop and should return immediately
  106. //! pair.second contains the task to be executed
  107. //!
  108. std::pair<bool, task_t> fetch_task_or_stop(void);
  109. //!
  110. //! \return whether the thread should stop or not
  111. //!
  112. bool should_stop(void) const;
  113. private:
  114. //!
  115. //! threads
  116. //!
  117. std::list<std::thread> m_workers;
  118. //!
  119. //! number of threads allowed
  120. //!
  121. std::atomic<std::size_t> m_max_nb_threads = ATOMIC_VAR_INIT(0);
  122. //!
  123. //! current number of running threads
  124. //!
  125. std::atomic<std::size_t> m_nb_running_threads = ATOMIC_VAR_INIT(0);
  126. //!
  127. //! whether the thread_pool should stop or not
  128. //!
  129. std::atomic<bool> m_should_stop = ATOMIC_VAR_INIT(false);
  130. //!
  131. //! tasks
  132. //!
  133. std::queue<task_t> m_tasks;
  134. //!
  135. //! tasks thread safety
  136. //!
  137. std::mutex m_tasks_mtx;
  138. //!
  139. //! task condvar to sync on tasks changes
  140. //!
  141. std::condition_variable m_tasks_condvar;
  142. };
  143. } // namespace utils
  144. } // namespace tacopie