How should a C11 thread pool safely wait for a specific task?

0
6
Asked By MellowCedar47 On

I have a basic multithreaded task pool in C11 that works well for fire-and-forget jobs. I now want to add a function that waits for one particular task to finish. Tasks are currently removed and freed after execution, so there is a race: while WaitForTask searches for a task and prepares its mutex and condition variable, a worker may finish and free the task. Moving the completion state into a separate structure avoids one use-after-free scenario, but a task could still finish before the waiting thread calls cnd_wait, causing the waiter to sleep forever. What is the correct synchronization pattern for waiting on a specific task, including how to avoid missed condition-variable signals and safely manage the task's lifetime?

2 Answers

Answered By QuietMarble8 On

A condition variable is not the state itself; it only wakes a thread when something might have changed. Give every task a completion state such as `finished` (and usually its result and status), protected by a mutex. The worker should lock that mutex, set `finished = true`, then signal or broadcast the condition variable while the mutex is still held. The waiting code must lock the same mutex and wait in a loop: `while (!finished) cnd_wait(&condition, &mutex);`. If the task completed before the waiter reached `cnd_wait`, the waiter sees `finished == true` and does not sleep, so there is no lost-wakeup problem.

MellowCedar47 -

A single condition variable for all completed tasks does not identify which task finished. I need the completion flag and synchronization state to be associated with the particular task being waited on, whether that is one completion object per task or a shared completion condition combined with a per-task predicate.

Answered By CopperLynx62 On

The completion object also needs a lifetime independent of the worker's `TaskData`. Do not destroy or free it immediately after one waiter returns unless you can prove there are no other users. Keep a reference count, store completion records separately until the task is reclaimed, or require the caller to own and destroy a task handle after waiting. The worker and waiter must never access a completion object after its last reference is released.

VividPine3 -

The same principle applies to the task record itself: protect status changes and task-list removal with the appropriate mutex, and do not free a record while another thread can still look it up or wait on it.

Related Questions

LEAVE A REPLY

Please enter your comment!
Please enter your name here

This site uses Akismet to reduce spam. Learn how your comment data is processed.