Skip to content

GH-48137: [C++] Restore ThreadPool state when a worker fails to start - #51107

Open
advitrocks9 wants to merge 1 commit into
apache:mainfrom
advitrocks9:fix-gh-48137
Open

GH-48137: [C++] Restore ThreadPool state when a worker fails to start#51107
advitrocks9 wants to merge 1 commit into
apache:mainfrom
advitrocks9:fix-gh-48137

Conversation

@advitrocks9

Copy link
Copy Markdown
Contributor

Rationale for this change

LaunchWorkersUnlocked appends to state_->workers_ before constructing the thread that owns
that entry, and only the worker itself erases it. If the std::thread constructor throws, the
entry stays, so Shutdown waits forever on workers_.empty(). The same throw escapes
SpawnReal after tasks_queued_or_running_ has been incremented, which wedges WaitForIdle,
and once stale entries fill workers_ to capacity the pool stops launching workers while
Spawn still returns OK for tasks nothing will run.

What changes are included in this PR?

The thread construction is wrapped so a failure erases the entry and rethrows, and the counter
is incremented only after the launch succeeds. Spawn already propagates std::system_error
from this path. Turning it into a Status would report success for a task with no worker.

Are these changes tested?

TestThreadPoolForkSafety.FailedWorkerLaunch forces a thread creation failure in a forked child,
then checks the pool is back to zero workers and zero tasks and still shuts down. It fails on
main, and reverting either hunk brings the failure back. The child skips if it cannot make thread
creation fail.

Are there any user-facing changes?

No. A failed spawn throws the same std::system_error and the pool stays usable.

@advitrocks9
advitrocks9 requested a review from pitrou as a code owner August 31, 2026 18:27
Copilot AI lite review requested due to automatic review settings August 31, 2026 18:27
@github-actions

Copy link
Copy Markdown

⚠️ GitHub issue #48137 has been automatically assigned in GitHub to PR creator.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes exception-safety holes in Arrow’s C++ ThreadPool worker-launch path so that a failed std::thread construction cannot leave the pool in a wedged state (stale workers_ entries and inflated tasks_queued_or_running_) that would hang Shutdown() / WaitForIdle() and eventually prevent new workers from being started.

Changes:

  • Make LaunchWorkersUnlocked() erase the just-appended workers_ entry if std::thread construction throws, then rethrow.
  • Move tasks_queued_or_running_ increment in SpawnReal() to after a successful worker launch attempt (keeping the launch heuristic equivalent).
  • Add a fork-based regression test that forces thread creation failure and asserts the pool returns to a clean state and can still shut down.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
cpp/src/arrow/util/thread_pool.h Adds FRIEND_TEST access for the new fork-safety regression test.
cpp/src/arrow/util/thread_pool.cc Restores ThreadPool internal invariants when worker thread creation throws; avoids counter leaks on launch failure.
cpp/src/arrow/util/thread_pool_test.cc Adds FailedWorkerLaunch regression test that validates state restoration after forced thread creation failure.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants