Namespaces
Variants
Views
Actions

std::execution::bulk, std::execution::bulk_chunked, std::execution::bulk_unchunked

From cppreference.com
< cpp‎ | execution
 
 
 
Defined in header <execution>
std::execution::sender

auto bulk( std::execution::sender auto input,
           std::integral auto size,
           auto&& policy,
           std::invocable<decltype(size),

                          /*values-sent-by*/(input)...> function );
(1) (since C++26)
std::execution::sender

auto bulk_chunked( std::execution::sender auto input,
                   std::integral auto size,
                   auto&& policy,
                   std::invocable<decltype(size), decltype(size),

                                  /*values-sent-by*/(input)...> function2 );
(2) (since C++26)
std::execution::sender

auto bulk_unchunked( std::execution::sender auto input,
                     std::integral auto size,
                     std::invocable<decltype(size), decltype(size),

                                    /*values-sent-by*/(input)...> function );
(3) (since C++26)

Contents

[edit] Parameters

input - sender which once executed sends the values upon which the function executes
policy - the execution policy attached to function/function2
function - invocable to be called for every index in range [0size), passing also the values produced by the input sender
function2 - same as function but called with a pair of indices (be), with b < e, so that, for each index i in range [[0size) there is exactly one call to function2 so that b <= i < e.

[edit] Return value

Returns a sender describing the task graph described by the input sender, with an added node of invoking the provided function with indices in range [0size), passing also the values sent by the input sender as arguments.

function/function2 is guaranteed to not begin executing until the returned sender is started.

[edit] Error completions

All errors passed in by input are forwarded.

In addition, the sender is allowed to complete with an std::exception_ptr error that contains:

  • any exception thrown by function
  • std::bad_alloc if the implementation fails to allocate required resources
  • an exception derived from std::runtime_error for other internal errors (e.g., cannot propagate the exception from the execution context to the caller).

[edit] Cancellation

The uncustomized std::execution::bulk, std::execution::bulk_chunk and std::execution::bulk_unchunked forward the stopped completion signal from input. They do not provide additional mechanism to produce stopped completion signal.

[edit] Notes

When calling std::execution::bulk and std::execution::bulk_chunked, different invocations of function/function2 may happen on the same execution agent.

When calling std::execution::bulk_unchunked, different invocations of function must happen on different execution agents.

The default implementation of std::execution::bulk is based on std::execution::bulk_chunked. While customizing std::execution::bulk is possible, it is expected that most of the time only std::execution::bulk_chunked is customized.

Without a customization of std::execution::bulk and std::execution::bulk_chunked, the behavior of std::execution::bulk and std::execution::bulk_chunk is to execute function serially, which is not particularly useful. Implementations are expected to have customizations that would make running std::execution::bulk and std::execution::bulk_chunked on different schedulers more useful.

std::execution::bulk_unchunked is meant to be used whenever function may have dependencies between different invocations, and it requires concurrent forward progress guarantees (parallel forward progress is not enough). Running std::execution::bulk_unchunked with a size of 1000 will require 1000 execution agents (e.g., threads) to run concurrently.

std::execution::bulk_unchunked does not require an execution policy, as is already expected for function to be able to run concurrently.

[edit] Examples

Possible usage of execution::bulk.

std::vector<double> x;
std::vector<double> y;
//...
sender auto process_elements
    = just(get_coefficient())
    | bulk(x.size(), [&](size_t i, double a)
    {
        y[i] = a * x[i] + y[i];
    });
// process_elements describes the work described by calling a function to
// get a coefficient `a`, and using it to execute
//   y[i] = a * x[i] + y[i]
// for each `i` in range [0, x.size())

Possible usage of execution::bulk_chunked.

std::vector<std::uint32_t> data = ...;
std::atomic<std::uint32_t> sum{0};
sender auto s = bulk_chunked(just(), par, 100000,
    [&sum, &data](int begin, int end)
    {
        auto partial_sum = std::accumulate(data.begin() + begin, data.begin() + end, 0U);
        sum.fetch_add(partial_sum);
    });
// the atomic object will not be touched 100000 times; will execute faster than bulk()