| 98 | */ |
| 99 | template <class R> |
| 100 | class FutureThreadPool final : public NonCopyableObj { |
| 101 | using Task = std::packaged_task<R()>; |
| 102 | std::deque<Task> m_tasks; |
| 103 | std::mutex m_mtx; |
| 104 | std::condition_variable m_cv_more_task; |
| 105 | |
| 106 | std::vector<std::thread> m_worker_threads; |
| 107 | std::vector<std::thread::id> m_worker_tids; |
| 108 | Maybe<std::string> m_name; |
| 109 | bool m_should_stop = true; |
| 110 | |
| 111 | void worker_impl(size_t id) { |
| 112 | { |
| 113 | MGB_LOCK_GUARD(m_mtx); |
| 114 | m_worker_tids.push_back(std::this_thread::get_id()); |
| 115 | } |
| 116 | |
| 117 | if (m_name.valid()) { |
| 118 | sys::set_thread_name(ssprintf("%s:%zu", m_name->c_str(), id)); |
| 119 | } |
| 120 | |
| 121 | for (;;) { |
| 122 | Task task; |
| 123 | for (;;) { |
| 124 | std::unique_lock<std::mutex> lk(m_mtx); |
| 125 | if (m_should_stop) |
| 126 | return; |
| 127 | if (!m_tasks.empty()) { |
| 128 | task = std::move(m_tasks.front()); |
| 129 | m_tasks.pop_front(); |
| 130 | break; |
| 131 | } |
| 132 | |
| 133 | m_cv_more_task.wait(lk); |
| 134 | } |
| 135 | task(); |
| 136 | } |
| 137 | } |
| 138 | |
| 139 | public: |
| 140 | using Future = std::future<R>; |
| 141 | |
| 142 | /*! |
| 143 | * \param name thread name for the workers |
| 144 | */ |
| 145 | FutureThreadPool(const Maybe<std::string>& name = None) : m_name{name} {} |
| 146 | |
| 147 | ~FutureThreadPool() { stop(); } |
| 148 | |
| 149 | /*! |
| 150 | * \brief launch a task with given function and args |
| 151 | */ |
| 152 | template <typename Func, typename... Args> |
| 153 | Future launch(Func&& func, Args&&... args) { |
| 154 | auto bfunc = std::bind(std::forward<Func>(func), std::forward<Args>(args)...); |
| 155 | |
| 156 | MGB_LOCK_GUARD(m_mtx); |
| 157 | m_tasks.emplace_back(std::move(bfunc)); |
nothing calls this directly
no test coverage detected