Skip to content

Clarifying the exception specification for bulk callback functions #2129

Description

@Cra3z

Do we really allow the bulk callback function to throw an exception? That is, when the bulk callback throws an exception, will that exception be propagated through the receiver's set_error(std::exception_ptr)?
Consider:
Given a scheduler sch, what should be the behavior of the following code?

try {
    stdexec::sync_wait(stdexec::schedule(sch) | stdexec::bulk(std::execution::par, 1uz, [](std::size_t){
        throw std::runtime_error{"xxx"}; 
    }));
}
catch (const std::runtime_error& e) { 
    ...
}

Can the try-catch here catch this std::runtime_error?
For the default implementation of bulk, the answer is yes, it can be caught. But for some customized bulk implementations, it may be different. For example, if sch here is a stdexec::parallel_scheduler, the program will terminate, see

void execute(size_t __begin, size_t __end) noexcept override
{
auto __state = reinterpret_cast<_BulkState*>(this);
if constexpr (_BulkState::__is_unchunked)
{
(void) __end; // not used
// If we are not parallelizing, we need to run all the iterations sequentially.
size_t __increments = 1;
if constexpr (!_BulkState::__parallelize)
{
__increments = static_cast<size_t>(__state->__size_);
}
for (size_t __i = __begin; __i < __begin + __increments; __i++)
{
std::apply([&](auto&&... __args) { __state->__fun_(__i, __args...); },
__base_t::__arguments_.__get());
}
}
else
{
// If we are not parallelizing, we need to pass the entire range to the functor.
if constexpr (!_BulkState::__parallelize)
{
__begin = 0;
__end = static_cast<size_t>(__state->__size_);
}
std::apply([&](auto&&... __args) { __state->__fun_(__begin, __end, __args...); },
__base_t::__arguments_.__get());
}
}

which does not handle the case where the call to __state->__fun_ throws an exception. However, fixing this seems a bit tricky, or should we reconsider the exception specification of bulk_item_receiver_proxy::execute?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions