TooManyCooks icon indicating copy to clipboard operation
TooManyCooks copied to clipboard

`tmc::fork_group`

Open tzcnt opened this issue 8 months ago • 0 comments

Similar to tmc::spawn_group. However, while spawn_group is mostly a convenience tool, fork_group solves some use cases that are otherwise difficult.

Currently there is no way to initiate a sequence of hot tasks (fork() them) one-by-one, and then wait for them all together. This is because forked tasks have a pointer to an atomic counter that must be initialized before they can run, and at the time they are created, it is unknown how many other tasks there will be. There are some workarounds used in various examples (atomic_awaitable, pushing to a channel) that are less than ideal.


tmc::fork_group creates the atomic counter up-front. It exposes an add() or fork() function which wraps any type of awaitable. The atomic counter must be incremented before the task is dispatched. This will likely necessitate a StoreLoad barrier. Once all the tasks have been forked, the fork_group can be co_awaited - after which it is "done" and should not be reused.

The only constraint on these awaitables is that they must return void - since there is no storage space allocated for them, as we don't know how many there will be. We can't use a vector as growing it will invalidate pointers from existing tasks.

Because there is no result storage, it should be zero-overhead to support any number of awaitables, with the overhead of each new awaitable being only the variable increment, and not any memory allocated to the fork_group.

tzcnt avatar Apr 16 '25 15:04 tzcnt