@@ -30,7 +30,7 @@ inline std::size_t normalize_thread_count(
3030
3131// Split [0, number_of_work_items) into n_threads contiguous chunks and invoke
3232// `chunk(thread_id, begin, end)` on each chunk. Thread 0 runs on the calling
33- // thread; threads 1..n_threads-1 run in parallel std::jthreads . The caller is
33+ // thread; threads 1..n_threads-1 run in parallel std::threads . The caller is
3434// responsible for picking n_threads via normalize_thread_count and for the
3535// thread safety of `chunk`.
3636//
@@ -70,17 +70,27 @@ void parallel_for_chunks(
7070 }
7171 };
7272
73- // jthread's destructor joins, so a failure while creating a later worker
74- // cannot destroy an earlier still-joinable thread and terminate the
75- // process. We still join explicitly below to rethrow only after all work
76- // has completed.
77- std::vector<std::jthread> threads;
73+ // A joinable std::thread whose destructor runs without a prior join calls
74+ // std::terminate. If spawning a later worker throws (e.g. the OS refuses a
75+ // new thread), the threads vector would otherwise destroy the already
76+ // joinable workers and terminate the process, so join them first and then
77+ // rethrow. (std::jthread would join on destruction automatically, but it is
78+ // not available in AppleClang's libc++, and portable macOS wheels are a
79+ // hard requirement.)
80+ std::vector<std::thread> threads;
7881 threads.reserve (n_threads > 0 ? n_threads - 1 : 0 );
79- for (std::size_t thread_id = 1 ; thread_id < n_threads; ++thread_id) {
80- const auto [begin, end] = bounds (thread_id);
81- threads.emplace_back ([thread_id, begin, end, &guarded_chunk]() {
82- guarded_chunk (thread_id, begin, end);
83- });
82+ try {
83+ for (std::size_t thread_id = 1 ; thread_id < n_threads; ++thread_id) {
84+ const auto [begin, end] = bounds (thread_id);
85+ threads.emplace_back ([thread_id, begin, end, &guarded_chunk]() {
86+ guarded_chunk (thread_id, begin, end);
87+ });
88+ }
89+ } catch (...) {
90+ for (auto &thread : threads) {
91+ thread.join ();
92+ }
93+ throw ;
8494 }
8595 const auto [begin, end] = bounds (0 );
8696 guarded_chunk (0 , begin, end);
0 commit comments