-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
run_loop::run-loop-sender should remove the item from the list when a stop-request is sent #293
Comments
Do you have any thoughts on what the wording change needs to be? This whole design space is difficult to get right so the gap isn't especially surprising. |
The remedy here would be to change the Then have The one with the stop-callback would call |
We could remove this for now, or make sync_wait do nothing but call start() and wait for completion (inline or not). The actual delegating version could be added later: It would remove functionality, in that it would be harder out of the box to implement concurrency on the current thread in the way that Another baby solution would be to simply rename |
One concern was that having We discussed several options in the meeting. We discussed removing One option was to make Then we could add a subsequent We also discussed the possibility of having an We also discussed another option similar to Concerns were raised about this approach with regards to its safety/composability. e.g. you would have to describe the work using Ideally a paper needs to explore this more - in particular the drivable_context concept and also forward-progress-delegation in general. Nobody had capacity to look into this at the moment, however. |
@lewissbaker what about renaming the current Also, related to this, you've mentioned the idea of a synchronously-cancelable scheduler. Do you have an API in mind? I'm picturing a scheduler that produces a move-only sender that has a auto snd = ex::schedule(sch);
auto handle = snd.handle();
auto state = ex::connect(std::move(snd), rec);
auto canceled = handle.sync_cancel();
assert(canceled);
state.start(); //< Completes in-line with set_stopped. I think that would let us do something similar to // The set_value() for the two inner receivers:
if (count.fetch_sub(1uz) == 2uz) {
// First thread out.
if (otherHandle.sync_cancel()) {
// We won and canceled the other. It'll never need our state.
ex::set_value(receiver);
} else {
// We failed to cancel the other one, so that thread must already be in flight.
// It'll get here in just a sec, so just let it take over.
}
} else {
// Second thread out.
if (ourHandle.sync_cancel_requested()) {
// The other thread won but would have seen that we were in flight,
// so it's expecting us to take over.
ex::set_value(receiver);
}
} Not sure if that's correct. I suspect there's a race in there but that it's fixable. :-D |
I was just thinking about having a query on a sender (in this case the schedule-sender) that lets you ask if a stop-request is synchronously-cancellable. The actual stop-request would still be sent in the same way (via stop-tokens) but the sender is guaranteeing that when a stop-request is sent to it that it is guaranteed to make forward progress and call the completion-handler (either set_stopped on the thread sending the stop-request) or set_value/set_error on some other thread, in the case that the operation has already completed and is being processed. |
I see. I really like reusing the existing cancelation API like that. So the way to detect if sync-canceling worked is to ask it to cancel and then see if the receiver got a |
The current specification for the
run_loop::schedule()
operation seems to be to just wait until the worker thread dequeues the task and only then check to see if a stop-request was sent - callingset_stopped()
if there was a stop-request, otherwise callingset_value()
.This could be problematic if trying to use
run_loop
with theget_delegation_scheduler
feature and could lead to deadlocks.For example, say someone schedules some work on another thread and wants to block waiting for that work to complete using
sync_wait()
. This will inject a run_loop scheduler as theget_delegation_scheduler
.The user, wanting to make use of the
get_delegation_scheduler
, schedules work on a composite scheduler that tries to use a primary scheduler, but also schedules to the delegation scheduler to allow the work to run in either the current thread or on some other context. This way, if all other threads on the other context are busy/blocked then we can still make forward progress on the task using the current thread.But this approach of scheduling a task on each scheduler and running on whichever completes first only really works if both of the schedulers support "synchronous cancellation". i.e. when a stop-request is sent then either it completes inline in the call to
request_stop()
withset_stopped()
or it is guaranteed to eventually complete withset_value()
. i.e. some thread has already dequeued the task and is about to/already callingset_value()
.This property allows whichever scheduler completed first to cancel the schedule operation on the other scheduler and then block waiting for the cancellation to finish before then continuing to signal completion.
However, the current specification of
run_loop
does not have this behaviour and so there is no guarantee that if the other scheduler completed first that the cancelled run_loop-schedule operation will complete in a timely manner (or at all).The text was updated successfully, but these errors were encountered: