97 const unsigned hw = std::thread::hardware_concurrency();
98 unsigned count = (hw > 1) ? (hw - 1) : 0;
100 const char* p = std::getenv(
"GROUP2_SERVER_THREADS");
101 if (p ==
nullptr || p[0] ==
'\0')
105 const unsigned long requested = std::strtoul(p, &end, 10);
109 constexpr unsigned k_maxFallbackWorkers = 64;
110 return static_cast<unsigned>(std::min<unsigned long>(requested, k_maxFallbackWorkers));
219#if defined(GROUP2_HAVE_TBB)
220 const auto distance = std::distance(begin, end);
222 tbb::parallel_for_each(begin, end, std::forward<Fn>(fn));
226 const auto distance = std::distance(begin, end);
230 const auto count =
static_cast<std::size_t
>(distance);
235 const std::size_t chunks = std::min<std::size_t>(count, workers + 1);
240 std::condition_variable cv;
241 std::size_t remaining = 0;
242 std::exception_ptr exception;
245 auto state = std::make_shared<WaitState>();
246 state->remaining = chunks - 1;
248 auto runChunk = [&](std::size_t chunk) {
249 const std::size_t first = (chunk * count) / chunks;
250 const std::size_t last = ((chunk + 1) * count) / chunks;
252 std::advance(it,
static_cast<decltype(distance)
>(first));
253 auto chunkEnd = begin;
254 std::advance(chunkEnd,
static_cast<decltype(distance)
>(last));
255 for (; it != chunkEnd; ++it) {
260 auto finish = [state](std::exception_ptr ex) {
261 std::lock_guard<std::mutex> lock(state->mutex);
262 if (ex && !state->exception)
263 state->exception = ex;
264 if (--state->remaining == 0)
265 state->cv.notify_one();
268 for (std::size_t chunk = 1; chunk < chunks; ++chunk) {
269 pool.
enqueue([&, finish, chunk] {
270 std::exception_ptr ex;
275 ex = std::current_exception();
281 std::exception_ptr mainException;
286 mainException = std::current_exception();
290 std::unique_lock<std::mutex> lock(state->mutex);
291 state->cv.wait(lock, [state] {
return state->remaining == 0; });
295 std::rethrow_exception(mainException);
296 if (state->exception)
297 std::rethrow_exception(state->exception);
303 std::for_each(begin, end, std::forward<Fn>(fn));