Libosmium: include/osmium/thread/pool.hpp Source File

Libosmium Fast and flexible C++ library for working with OpenStreetMap data

Loading...
Searching...
No Matches
pool.hpp
Go to the documentation of this file.
1#ifndef OSMIUM_THREAD_POOL_HPP
2#define OSMIUM_THREAD_POOL_HPP
3
4/*
5
6This file is part of Osmium (https://osmcode.org/libosmium).
7
8Copyright 2013-2026 Jochen Topf <jochen@topf.org> and others (see README).
9
10Boost Software License - Version 1.0 - August 17th, 2003
11
12Permission is hereby granted, free of charge, to any person or organization
13obtaining a copy of the software and accompanying documentation covered by
14this license (the "Software") to use, reproduce, display, distribute,
15execute, and transmit the Software, and to prepare derivative works of the
16Software, and to permit third-parties to whom the Software is furnished to
17do so, all subject to the following:
18
19The copyright notices in the Software and this entire statement, including
20the above license grant, this restriction and the following disclaimer,
21must be included in all copies of the Software, in whole or in part, and
22all derivative works of the Software, unless such copies or derivative
23works are solely in the form of machine-executable object code generated by
24a source language processor.
25
26THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
29SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
30FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
31ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32DEALINGS IN THE SOFTWARE.
33
34*/
35
36#include <osmium/thread/function_wrapper.hpp>
37#include <osmium/thread/queue.hpp>
38#include <osmium/thread/util.hpp>
39#include <osmium/util/config.hpp>
40
41#include <cstddef>
42#include <future>
43#include <thread>
44#include <type_traits>
45#include <utility>
46#include <vector>
47
48namespace osmium {
49
53 namespace thread {
54
55 namespace detail {
56
57 // Maximum number of allowed pool threads (just to keep the user
58 // from setting something silly).
59 enum {
60 max_pool_threads = 32
61 };
62
63 inline int get_pool_size(int num_threads, int user_setting, unsigned hardware_concurrency) {
64 if (num_threads == 0) {
65 num_threads = user_setting ? user_setting : -2;
66 }
67
68 if (num_threads < 0) {
69 num_threads += static_cast<int>(hardware_concurrency);
70 }
71
72 if (num_threads < 1) {
73 num_threads = 1;
74 } else if (num_threads > max_pool_threads) {
75 num_threads = max_pool_threads;
76 }
77
78 return num_threads;
79 }
80
81 inline std::size_t get_work_queue_size() noexcept {
82 return osmium::config::get_max_queue_size("WORK", 10);
83 }
84
85 } // namespace detail
86
90 class Pool {
91
96 class thread_joiner {
97
98 std::vector<std::thread>& m_threads;
99
100 public:
101
102 explicit thread_joiner(std::vector<std::thread>& threads) :
103 m_threads(threads) {
104 }
105
106 thread_joiner(const thread_joiner&) = delete;
107 thread_joiner& operator=(const thread_joiner&) = delete;
108
109 thread_joiner(thread_joiner&&) = delete;
110 thread_joiner& operator=(thread_joiner&&) = delete;
111
112 ~thread_joiner() {
113 for (auto& thread : m_threads) {
114 if (thread.joinable()) {
115 thread.join();
116 }
117 }
118 }
119
120 }; // class thread_joiner
121
122 osmium::thread::Queue<function_wrapper> m_work_queue;
123 std::vector<std::thread> m_threads;
124 thread_joiner m_joiner;
125 int m_num_threads;
126
127 void worker_thread() {
128 osmium::thread::set_thread_name("_osmium_worker");
129 while (true) {
130 function_wrapper task;
131 m_work_queue.wait_and_pop(task);
132 if (task && task()) {
133 // The called tasks returns true only when the
134 // worker thread should shut down.
135 return;
136 }
137 }
138 }
139
140 public:
141
142 enum {
143 default_num_threads = 0
144 };
145
146 enum {
147 default_queue_size = 0U
148 };
149
165 explicit Pool(int num_threads = default_num_threads, std::size_t max_queue_size = default_queue_size) :
166 m_work_queue(max_queue_size > 0 ? max_queue_size : detail::get_work_queue_size(), "work"),
167 m_joiner(m_threads),
168 m_num_threads(detail::get_pool_size(num_threads, osmium::config::get_pool_threads(), std::thread::hardware_concurrency())) {
169
170 try {
171 for (int i = 0; i < m_num_threads; ++i) {
172 m_threads.emplace_back(&Pool::worker_thread, this);
173 }
174 } catch (...) {
175 shutdown_all_workers();
176 throw;
177 }
178 }
179
186 static Pool& default_instance() {
187 static Pool pool{};
188 return pool;
189 }
190
191 void shutdown_all_workers() {
192 for (int i = 0; i < m_num_threads; ++i) {
193 // The special function wrapper makes a worker shut down.
194 m_work_queue.push(function_wrapper{0});
195 }
196 }
197
198 Pool(const Pool&) = delete;
199 Pool& operator=(const Pool&) = delete;
200
201 Pool(Pool&&) = delete;
202 Pool& operator=(Pool&&) = delete;
203
204 ~Pool() {
205 shutdown_all_workers();
206 }
207
208 int num_threads() const noexcept {
209 return m_num_threads;
210 }
211
212 std::size_t queue_size() const {
213 return m_work_queue.size();
214 }
215
216 bool queue_empty() const {
217 return m_work_queue.empty();
218 }
219
220#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
221 // std::result_of is deprecated in C++17 and removed in C++20,
222 // so we use std::invoke_result_t.
223 template <typename TFunction>
224 using submit_func_result_type = std::invoke_result_t<TFunction>;
225#else
226 // For C++11 and C++14
227 template <typename TFunction>
228 using submit_func_result_type = std::result_of_t<TFunction()>;
229#endif
230
231 template <typename TFunction>
232 std::future<submit_func_result_type<TFunction>> submit(TFunction&& func) {
233 std::packaged_task<submit_func_result_type<TFunction>()> task{std::forward<TFunction>(func)};
234 std::future<submit_func_result_type<TFunction>> future_result{task.get_future()};
235 m_work_queue.push(std::move(task));
236
237 return future_result;
238 }
239
240 }; // class Pool
241
242 } // namespace thread
243
244} // namespace osmium
245
246#endif // OSMIUM_THREAD_POOL_HPP
osmium::thread::Pool::thread_joiner
Definition pool.hpp:96
osmium::thread::Pool::thread_joiner::thread_joiner
thread_joiner(std::vector< std::thread > &threads)
Definition pool.hpp:102
osmium::thread::Pool::thread_joiner::thread_joiner
thread_joiner(thread_joiner &&)=delete
osmium::thread::Pool::thread_joiner::m_threads
std::vector< std::thread > & m_threads
Definition pool.hpp:98
osmium::thread::Pool::thread_joiner::thread_joiner
thread_joiner(const thread_joiner &)=delete
osmium::thread::Pool::thread_joiner::operator=
thread_joiner & operator=(thread_joiner &&)=delete
osmium::thread::Pool::thread_joiner::operator=
thread_joiner & operator=(const thread_joiner &)=delete
osmium::thread::Pool::thread_joiner::~thread_joiner
~thread_joiner()
Definition pool.hpp:112
osmium::thread::Pool::submit_func_result_type
std::result_of_t< TFunction()> submit_func_result_type
Definition pool.hpp:228
osmium::thread::Pool::shutdown_all_workers
void shutdown_all_workers()
Definition pool.hpp:191
osmium::thread::Pool::m_threads
std::vector< std::thread > m_threads
Definition pool.hpp:123
osmium::thread::Pool::~Pool
~Pool()
Definition pool.hpp:204
osmium::thread::Pool::Pool
Pool(int num_threads=default_num_threads, std::size_t max_queue_size=default_queue_size)
Definition pool.hpp:165
osmium::thread::Pool::Pool
Pool(Pool &&)=delete
osmium::thread::Pool::queue_size
std::size_t queue_size() const
Definition pool.hpp:212
osmium::thread::Pool::default_queue_size
@ default_queue_size
Definition pool.hpp:147
osmium::thread::Pool::submit
std::future< submit_func_result_type< TFunction > > submit(TFunction &&func)
Definition pool.hpp:232
osmium::thread::Pool::default_instance
static Pool & default_instance()
Definition pool.hpp:186
osmium::thread::Pool::Pool
Pool(const Pool &)=delete
osmium::thread::Pool::operator=
Pool & operator=(Pool &&)=delete
osmium::thread::Pool::m_work_queue
osmium::thread::Queue< function_wrapper > m_work_queue
Definition pool.hpp:122
osmium::thread::Pool::default_num_threads
@ default_num_threads
Definition pool.hpp:143
osmium::thread::Pool::m_joiner
thread_joiner m_joiner
Definition pool.hpp:124
osmium::thread::Pool::queue_empty
bool queue_empty() const
Definition pool.hpp:216
osmium::thread::Pool::worker_thread
void worker_thread()
Definition pool.hpp:127
osmium::thread::Pool::m_num_threads
int m_num_threads
Definition pool.hpp:125
osmium::thread::Pool::operator=
Pool & operator=(const Pool &)=delete
osmium::thread::Pool::num_threads
int num_threads() const noexcept
Definition pool.hpp:208
osmium::thread::Queue
Definition queue.hpp:57
osmium::thread::function_wrapper
Definition function_wrapper.hpp:48
config.hpp
function_wrapper.hpp
detail
Definition attr.hpp:342
osmium::config
Definition config.hpp:60
osmium::config::get_max_queue_size
std::size_t get_max_queue_size(const char *queue_name, const std::size_t default_value) noexcept
Definition config.hpp:83
osmium::thread
Threading-related low-level code.
Definition function_wrapper.hpp:41
osmium::thread::set_thread_name
void set_thread_name(const char *name) noexcept
Definition util.hpp:78
osmium
Namespace for everything in the Osmium library.
Definition assembler.hpp:53
std
Definition location.hpp:654
queue.hpp
util.hpp