-
Notifications
You must be signed in to change notification settings - Fork 235
parallel_scheduler can have incorrect error completion #1991
Description
stdexec::parallel_scheduler will sometimes have an error completion when it shouldn't. (At least on Linux; I can't easily test other platforms.) This causes compilation errors when the receiver is not set up to handle errors. exec::static_thread_pool does not have this problem even though parallel_scheduler is built on top of static_thread_pool on Linux.
If I understand correctly, the sender passed to spawn cannot have an error completion, because spawn doesn't have any mechanism to report errors.
When I spawn a sender chain containing a then onto a static_thread_pool, I can avoid the error completion by having the lambda for the then be explicitly noexcept. For example, this works:
$ cat spawnpoolthen.cpp
#include <stdexec/execution.hpp>
#include <exec/static_thread_pool.hpp>
int main() {
exec::static_thread_pool pool{10};
auto sch = pool.get_scheduler();
stdexec::simple_counting_scope scope;
stdexec::spawn(stdexec::schedule(sch) | stdexec::then([]()noexcept{}),
scope.get_token());
stdexec::sync_wait(scope.join());
}
$ g++ -std=c++23 -DSTDEXEC_SYSTEM_CONTEXT_HEADER_ONLY -I/proj/cuda/stdexec/main/include spawnpoolthen.cpp -ltbb
$But when I use stdexec::parallel_scheduler instead of static_thread_pool, the then sender has an error completion even if the lambda is nexcept. For example, on Linux:
alder1:~/.../stdexec/tests/experiment $ cat spawnparthen.cpp
#include <stdexec/execution.hpp>
int main() {
auto sch = stdexec::get_parallel_scheduler();
stdexec::simple_counting_scope scope;
stdexec::spawn(stdexec::schedule(sch) | stdexec::then([]()noexcept{}),
scope.get_token());
stdexec::sync_wait(scope.join());
}
alder1:~/.../stdexec/tests/experiment $ g++ -std=c++23 -DSTDEXEC_SYSTEM_CONTEXT_HEADER_ONLY -I/proj/cuda/stdexec/main/include spawnparthen.cpp -ltbb
[... snip ...]
/proj/cuda/stdexec/main/include/stdexec/__detail/__basic_sender.hpp:207:15: error: no match for call to ‘(stdexec::set_error_t) (stdexec::__spawn::__spawn_receiver, std::__exception_ptr::exception_ptr)’
207 | _Set()(static_cast<_State&&>(__state).__rcvr_, static_cast<_As&&>(__as)...);
| ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[... snip ...]To work around this bug, I need to add a do-nothing upon_error that swallows the error that cannot happen:
$ cat spawnparthenwar.cpp
#include <stdexec/execution.hpp>
int main() {
auto sch = stdexec::get_parallel_scheduler();
stdexec::simple_counting_scope scope;
stdexec::spawn(stdexec::schedule(sch) | stdexec::then([]()noexcept{}) |
stdexec::upon_error([](auto)noexcept{}),
scope.get_token());
stdexec::sync_wait(scope.join());
}
$ g++ -std=c++23 -DSTDEXEC_SYSTEM_CONTEXT_HEADER_ONLY -I/proj/cuda/stdexec/main/include spawnparthenwar.cpp -ltbb
$I don't think that workaround should be necessary.