Skip to content

parallel_scheduler can have incorrect error completion #1991

@dkolsen-pgi

Description

@dkolsen-pgi

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions