How can I close a thread pool and cancel all work that had been queued to it?

Raymond Chen

When you close a custom Win32 thread pool, the call to Close­Threadpool returns immediately, but the actual closure doesn’t occur until all pending work has completed. What if you want to abandon any work that hasn’t yet begun?

What you can do is put the work items in a thread pool cleanup group, and when you want to abandon all of the pending callbacks, call Close­Threadpool­Cleanup­Group­Members and pass TRUE for fCancel­Pending­Callbacks. The function abandons any callbacks that haven’t started but waits for for callbacks that have already started.¹

Here’s a sample, with no error checking.

auto pool = CreateThreadpool(0);
auto group = CreateThreadpoolCleanupGroup();

TP_CALLBACK_ENVIRON env;
InitializeThreadpoolEnvironment(&env);
SetThreadpoolCallbackPool(&env, pool);
SetThreadpoolCallbackCleanupGroup(&env, group, nullptr);

// Queue up 100 slow-running tasks.
auto callback = [](auto instance, auto context, auto work)
    {
        printf("%d\n", PtrToInt(context));
        Sleep(100);
    };
for (int i = 0; i < 100; i++)
{
    auto work = CreateThreadpoolWork(callback, IntToPtr(i), &env);
    SubmitThreadpoolWork(work);
}

// Shut down the entire group.
// Any callbacks that haven't started will be abandoned.
CloseThreadpoolCleanupGroupMembers(group, TRUE, nullptr);

// Clean up the thread pool when done.
CloseThreadpool(pool);

¹ If you want the ones that have already started to respond to the shutdown, you can create a custom signal and have each callback explicitly periodically check that custom signal themselves.

1 comment

Comments are closed. Login to edit/delete your existing comments

  • Jan Ringoš 0

    The Vista thread pool is extremely fun to abstract into C++. So many opportunities for a callback to complete on object that’s long gone. So many opportunities for deadlocks.

Feedback usabilla icon