Skip to content

Executor types remove circular refs#400

Merged
jbaldwin merged 6 commits into
mainfrom
executor-circular-refs
Oct 9, 2025
Merged

Executor types remove circular refs#400
jbaldwin merged 6 commits into
mainfrom
executor-circular-refs

Conversation

@jbaldwin

@jbaldwin jbaldwin commented Oct 8, 2025

Copy link
Copy Markdown
Owner

The executors are circular ref'ing with the std::shared_ptr being copied into worker threads for coro::thread_pool and coro::io_scheduler (spawn mode).

I've determined that using std::shared_ptr is not the way to go since it gives an indeterminate destruction time, which can cause the coro::thread_pool or coro::io_scheduler to be destroyed on one of the threads running coroutines, possibly joining to itself and causing a SIGABRT. This should have been expected and I missed it and didn't consider the consequences and thought that using std::shared_ptr would make sure all the task constructs and the executors would keep each other alive. It did, since the executors circular referenced themselves, but without that circular reference the destruction is indeterminate as pointed out and cannot be reliably controlled. I think this means the best course of action is to revert to using std::unique_ptr for all executor types and force the user to make sure it lives for the correct livetime, and gets destroyed at the appropriate time on the correct thread.

@jbaldwin jbaldwin self-assigned this Oct 8, 2025
@jbaldwin jbaldwin force-pushed the executor-circular-refs branch from 4cd3361 to e5298bc Compare October 8, 2025 14:50
The executors are circular ref'ing with the std::shared_ptr being copied
into worker threads for coro::thread_pool and coro::io_scheduler (spawn
mode).

I'm leaving all other construct types that take an executor by
shared_ptr to continue to do so, its important that the executors they
run on do not destruct until all the tasks are completed, so the user
needs to take care to destroy objects in a meaningful way so the
executor is the last object to destruct.
Have not switched coro::condition_variable or other constructs (but
likely need to?)
I think shared_ptr usage is just flawed since it means that any
lingering coroutine could destruct the executors. This will force the
user to make sure it outlives any coroutines at the cost of possibly
runtime nullptr references if they are going to use it past the lifetime
of the executor.

@wence- wence- 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.

This looks good to me, I tried it out in our larger application and everything seems good (in combination with #399). (We're not using any of the io_scheduler/networking features so not affected by any changes there).

Trivial nitpicks around some comments.

Comment thread src/io_scheduler.cpp Outdated
Comment thread src/thread_pool.cpp Outdated
Comment thread include/coro/shared_mutex.hpp Outdated
@jbaldwin jbaldwin merged commit 276b19c into main Oct 9, 2025
53 checks passed
@jbaldwin jbaldwin deleted the executor-circular-refs branch October 9, 2025 16:13
@jbaldwin jbaldwin linked an issue Oct 9, 2025 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

deadlock/missing wake in condition_variable notify_all?

2 participants