Spec-Zone.ru › C++

Библиотека управления выполнением (начиная с C++26)

Библиотека управления выполнением предоставляет среду для управления асинхронным выполнением на универсальных ресурсах выполнения.

Цель библиотеки — предоставить типы словаря для асинхронных операций и дать возможность простым и компонуемым способом строить графы выполнения задач.

Общие определения библиотеки

  • Отправитель: описание асинхронной работы, предназначенной для выполнения. Создаёт состояние операции (см. ниже).
    • Отправители асинхронно «отправляют» свои результаты слушателям, называемым «получателями» (см. ниже).
    • Отправители можно объединять в графы задач с помощью универсальных алгоритмов.
    • Фабрики отправителей и адаптеры — универсальные алгоритмы, которые заключают распространённые асинхронные шаблоны в объекты, удовлетворяющие концепции sender.
    • С отправителем связан «объект, поддерживающий запросы» (см. ниже), называемый атрибутами отправителя, который описывает различные характеристики отправителя и создаваемых им асинхронных операций.
  • Получатель: обобщённый обратный вызов, который использует или «получает» асинхронные результаты, созданные отправителем.
    • У получателей есть три различных «канала», по которым отправитель может передавать результаты: успешное завершение, ошибка и отмена, называемые соответственно «значением», «ошибкой» и «остановкой».
    • Получатели предоставляют расширяемую среду выполнения: «объект, поддерживающий запросы» (см. ниже), который потребитель может использовать для настройки асинхронной операции.
  • Состояние операции: объект, содержащий состояние, необходимое асинхронной операции.
    • Отправитель и получатель связываются при передаче функции std::execution::connect.
    • Результатом связывания отправителя и получателя является состояние операции.
    • Работа не ставится в очередь на выполнение, пока для состояния операции не вызвана функция «start».
    • После запуска время жизни состояния операции не может завершиться до окончания асинхронной операции, а его адрес должен оставаться неизменным.
  • Агент выполнения: сущность, например поток, которая может выполнять работу параллельно с другими агентами выполнения.
    • Реализации или пользователи могут вводить другие виды агентов, например процессы или задачи пула потоков.
  • Ресурс выполнения: сущность программы, также называемая контекстом выполнения, которая управляет (возможно, динамическим) набором агентов выполнения.
    • Текущий активный поток, предоставляемый системой пул потоков и использование API, связанного с внешним аппаратным ускорителем, — всё это примеры ресурсов выполнения.
  • Планировщик: лёгкий дескриптор ресурса выполнения, предназначенный для планирования работы на этом ресурсе.
    • Планировщик — это фабрика отправителя, который завершает работу с получателем от агента выполнения, принадлежащего ресурсу выполнения.
  • Объект, поддерживающий запросы: доступная только для чтения коллекция пар «ключ/значение», в которой каждый ключ — объект точки настройки, называемый «объектом запроса».
    • Запрос — это вызов объекта запроса, которому в качестве первого аргумента передаётся объект, поддерживающий запросы, а также (возможно, пустой) набор дополнительных аргументов. Запрос задаёт синтаксические и семантические требования к своим вызовам.

Утилиты библиотеки

Концепции

Планировщики

Определено в заголовке <execution>
Определено в пространстве имён std::execution
execution::scheduler
(C++26)
задаёт требования, которым должен соответствовать тип, являющийся планировщиком
(концепция)

Отправители

Определено в заголовке <execution>
Определено в пространстве имён std::execution
execution::sender
(C++26)
задаёт требования, которым должен соответствовать тип, являющийся отправителем
(концепция)
execution::sender_in
(C++26)
задаёт требования к отправителю, который может создавать асинхронные операции для заданного связанного типа среды
(концепция)
execution::dependent_sender
(C++26)
задаёт требования к типу отправителя, сигнатуры завершения которого невозможно определить независимо от его среды выполнения
(концепция)

Получатели

Определено в заголовке <execution>
Определено в пространстве имён std::execution
execution::receiver
(C++26)
задаёт требования, которым должен соответствовать тип, являющийся получателем
(концепция)
execution::inlinable_receiver
(C++26)
задаёт требования к получателю, который можно восстановить по требованию по указателю на объект состояния операции, созданный при связывании получателя с отправителем
(концепция)

Состояния операций

Определено в заголовке <execution>
Определено в пространстве имён std::execution
execution::operation_state
(C++26)
задаёт требования, которым должен соответствовать тип, являющийся состоянием операции
(концепция)

Асинхронные области видимости

Определено в заголовке <execution>
Определено в пространстве имён std::execution
execution::scope_association
(C++26)
задаёт требования к дескриптору RAII, представляющему активную связь с асинхронной областью видимости
(концепция)
execution::scope_token
(C++26)
задаёт невладеющий дескриптор асинхронной области видимости, который ведёт себя как ссылка на асинхронную область видимости
(концепция)

Вспомогательные компоненты

Контексты выполнения

Определено в заголовке <execution>
Определено в пространстве имён std::execution
execution::run_loop
(C++26)
ресурс выполнения, содержащий потокобезопасную очередь задач MPSC и управляемый вручную цикл событий
(класс)

Домены выполнения

Определено в заголовке <execution>
Определено в пространстве имён std::execution
execution::default_domain
(C++26)
тип-тег домена выполнения по умолчанию, который выбирает преобразования на основе тега отправителя
(класс)
execution::transform_sender
(C++26)
преобразует отправитель в новый отправитель в заданном домене выполнения
(шаблон функции)
execution::apply_sender
(C++26)
использует отправитель с заданным тегом потребителя отправителя и набором аргументов и возвращает результат в заданном домене выполнения
(шаблон функции)

Гарантия продвижения вперёд

Определено в заголовке <execution>
Определено в пространстве имён std::execution
execution::forward_progress_guarantee
(C++26)
задаёт гарантию продвижения вперёд для агентов выполнения, созданных связанным ресурсом выполнения планировщика
(перечисление)

Среды

Определено в заголовке <execution>
Определено в пространстве имён std::execution
execution::prop
(C++26)
создаёт объект, поддерживающий запросы, из объекта запроса и значения
(шаблон класса)
execution::env
(C++26)
объединяет несколько объектов, поддерживающих запросы, в один такой объект
(шаблон класса)
execution::get_env
(C++26)
возвращает связанный объект, поддерживающий запросы, для заданного аргумента
(объект точки настройки)

Запросы

Определено в заголовке <execution>
forwarding_query
(C++26)
спрашивает у объекта запроса, следует ли передавать его через адаптеры объектов, поддерживающих запросы
(объект точки настройки)
get_allocator
(C++26)
запрашивает у объекта, поддерживающего запросы, связанный с ним распределитель памяти
(объект точки настройки)
get_stop_token
(C++26)
запрашивает у объекта, поддерживающего запросы, связанный с ним токен остановки
(объект точки настройки)
execution::get_domain
(C++26)
запрашивает у объекта, поддерживающего запросы, связанный с ним тег домена выполнения
(объект точки настройки)
execution::get_completion_domain
(C++26)
запрашивает домен завершения, связанный с тегом завершения из атрибутов отправителя
(объект точки настройки)
execution::get_scheduler
(C++26)
запрашивает у объекта, поддерживающего запросы, связанный с ним планировщик
(объект точки настройки)
execution::get_start_scheduler
(C++26)
запрашивает у среды получателя планировщик, в котором будет запущено состояние операции, созданное с этим получателем.
(объект точки настройки)
execution::get_delegation_scheduler
(C++26)
запрашивает у объекта, поддерживающего запросы, планировщик, которому можно делегировать работу для обеспечения делегирования продвижения вперёд
(объект точки настройки)
execution::get_completion_scheduler
(C++26)
получает планировщик завершения, связанный с тегом завершения из атрибутов отправителя
(объект точки настройки)
execution::get_forward_progress_guarantee
(C++26)
запрашивает у планировщика его execution::forward_progress_guarantee
(объект точки настройки)
execution::get_await_completion_adaptor
(C++26)
запрашивает у объекта, поддерживающего запросы, связанный с ним адаптер завершения для await
(объект точки настройки)

Сигнатуры завершения

Определено в заголовке <execution>
Определено в пространстве имён std::execution
execution::completion_signatures
(C++26)
тип, кодирующий набор сигнатур завершения
(шаблон класса)
execution::get_completion_signatures
(C++26)
получает сигнатуры завершения отправителя
(объект точки настройки)
execution::tag_of_t
(C++26)
получает тип тега отправителя
(шаблон псевдонима)
execution::value_types_of_t
(C++26)
получает тип завершения значением отправителя
(шаблон псевдонима)
execution::error_types_of_t
(C++26)
получает тип завершения ошибкой отправителя
(шаблон псевдонима)
execution::sends_stopped
(C++26)
определяет, поддерживает ли отправитель завершение остановкой
(шаблон переменной)

Утилиты корутин

Определено в заголовке <execution>
Определено в пространстве имён std::execution
execution::as_awaitable
(C++26)
преобразует выражение в объект, доступный для await, в рамках определённой корутины
(объект точки настройки)
execution::with_awaitable_senders
(C++26)
при использовании в качестве базового класса типа promise корутины позволяет ожидать отправители в рамках этого типа корутины
(шаблон класса)
execution::affine
(C++26)
адаптирует отправитель так, чтобы он завершался в планировщике получателя. Если алгоритм определяет, что адаптированный отправитель уже завершается в нужном планировщике, он может избежать операции планирования
(объект точки настройки)
execution::inline_scheduler
(C++26)
простой планировщик, который немедленно и синхронно завершает выполнение в потоке, вызывающем std::execution::start для состояния операции, созданного его отправителем
(класс)
execution::task
(C++26)
представляет отправитель, который можно использовать в качестве возвращаемого типа функций-корутин
(шаблон класса)
execution::task_scheduler
(C++26)
предоставляет единообразный интерфейс со стиранием типа, позволяющий хранить, передавать и вызывать операции планирования для произвольных безошибочных планировщиков
(класс)

Асинхронные области видимости

Определено в заголовке <execution>
Определено в пространстве имён std::execution
execution::simple_counting_scope
(C++26)
лёгкая асинхронная область видимости со счётчиком ссылок. Отслеживает количество выполняющихся в данный момент асинхронных операций, динамически порождённых в этой области
(класс)
execution::counting_scope
(C++26)
отличается от simple_counting_scope поддержкой отмены
(класс)

Параллельный планировщик

Определено в заголовочном файле <execution>
Определено в пространстве имён std::execution
execution::parallel_scheduler
(C++26)
представляет дескриптор общего глобального ресурса выполнения (например, системного пула потоков, предоставляемого ОС), оптимизированного для параллельного выполнения
(класс)
execution::get_parallel_scheduler
(C++26)
возвращает экземпляр parallel_scheduler, представляющий общий контекст параллельного выполнения в приложении. последовательные вызовы этой функции возвращают объекты планировщика, ссылающиеся на один и тот же базовый глобальный пул потоков
(функция)
Определено в пространстве имён std::execution::parallel_scheduler_replacement
parallel_scheduler_replacement:: receiver_proxy
(C++26)
представляет получателя, который будет уведомлён реализациями parallel_scheduler_backend для запуска операций завершения
(класс)
parallel_scheduler_replacement:: bulk_item_receiver_proxy
(C++26)
используется для настроек bulk_chunked и bulk_unchunked, которые также будут получать уведомления от реализаций parallel_scheduler_backend, соответствующие различным итерациям
(класс)
parallel_scheduler_replacement:: parallel_scheduler_backend
(C++26)
служит абстрактным связующим звеном между пользовательским parallel_scheduler и внутренним ресурсом выполнения (например, системным пулом потоков, предоставляемым ОС)
(класс)
parallel_scheduler_replacement:: query_parallel_scheduler_backend
(C++26)
возвращает shared_ptr<parallel_scheduler_backend>, представляющий общий контекст параллельного выполнения в приложении. последовательные вызовы этой функции возвращают shared_ptr, указывающие на один и тот же объект parallel_scheduler_backend
(функция)

Основные операции

Состояние операции

Определено в заголовочном файле <execution>
Определено в пространстве имён std::execution
execution::connect
(C++26)
соединяет sender с receiver
(объект-точка настройки)
execution::start
(C++26)
запускает асинхронную операцию, связанную с объектом operation_state
(объект-точка настройки)

Функции завершения

Эти функции вызываются отправителями, чтобы сообщить получателям о завершении работы.

Определено в заголовочном файле <execution>
Определено в пространстве имён std::execution
execution::set_value
(C++26)
функция завершения со значением, указывающая на успешное завершение
(объект-точка настройки)
execution::set_error
(C++26)
функция завершения с ошибкой, указывающая, что при вычислении или планировании произошла ошибка
(объект-точка настройки)
execution::set_stopped
(C++26)
функция завершения с остановкой, указывающая, что операция закончилась до достижения успеха или ошибки
(объект-точка настройки)

Алгоритмы отправителей

Фабрики отправителей

Фабрика отправителей — это функция, возвращающая отправитель, параметры которой имеют типы, удовлетворяющие концепту sender false.

К фабрикам отправителей относятся:

Определено в заголовочном файле <execution>
Определено в пространстве имён std::execution
execution::just
(C++26)
принимает произвольное количество аргументов и возвращает отправитель, который при соединении и запуске завершается синхронно, передавая аргументы функции завершения со значением получателя
(объект-точка настройки)
execution::just_error
(C++26)
принимает один аргумент и возвращает отправитель, который при соединении и запуске завершается синхронно, передавая аргумент функции завершения с ошибкой получателя
(объект-точка настройки)
execution::just_stopped
(C++26)
создаёт отправитель, который немедленно завершается вызовом set_stopped своего получателя
(объект-точка настройки)
execution::read_env
(C++26)
создаёт отправитель, который запрашивает среду, связанную с его получателем
(объект-точка настройки)
execution::schedule
(C++26)
подготавливает граф задач к выполнению с помощью заданного планировщика
(объект-точка настройки)

Адаптеры отправителей, объединяемые в конвейер

Определено в заголовочном файле <execution>
Определено в пространстве имён std::execution
execution::sender_adaptor_closure
(C++26)
вспомогательный базовый шаблон класса для определения объекта-замыкания адаптера отправителя, объединяемого в конвейер
(шаблон класса)

Адаптеры отправителей

Адаптер отправителя — это функция, возвращающая отправитель, среди параметров которой есть как минимум один параметр с типом, удовлетворяющим концепту sender, причём возвращаемый отправитель является родительским отправителем аргументов-отправителей этой функции-адаптера.

К адаптерам отправителей относятся:

Определено в заголовочном файле <execution>
Определено в пространстве имён std::execution
execution::write_env
(C++26)
внедряет значения в среду, доступную заданному отправителю, — переопределяя или дополняя сведения, предоставляемые конечным получателем
(объект-точка настройки)
execution::unstoppable
(C++26)
защищает заданный отправитель от внешних запросов на отмену, обеспечивая непрерывное выполнение критической задачи до завершения
(объект-точка настройки)
execution::starts_on
(C++26)
преобразует заданный отправитель в отправитель, который запускает выполнение с использованием ресурса выполнения заданного планировщика
(объект-точка настройки)
execution::continues_on
(C++26)
преобразует заданный отправитель в отправитель, который завершается с использованием ресурса выполнения заданного планировщика
(объект-точка настройки)
execution::on
(C++26)
преобразует заданный отправитель, перенося выполнение на ресурс выполнения заданного планировщика, где выполняется отправитель или продолжение, а затем возвращая выполнение исходному ресурсу
(объект-точка настройки)
execution::schedule_from
(C++26)
планирует выполнение работы, зависящей от завершения заданного отправителя, на ресурсе выполнения заданного планировщика
(объект-точка настройки)
execution::then
(C++26)
добавляет в граф задач после входного отправителя узел, представляющий вызов заданной функции с переданными входным отправителем значениями в качестве аргументов
(объект-точка настройки)
execution::upon_error
(C++26)
добавляет в граф задач после входного отправителя узел, представляющий вызов заданной функции с ошибкой, переданной входным отправителем, если произошла ошибка
(объект-точка настройки)
execution::upon_stopped
(C++26)
добавляет в граф задач после входного отправителя узел, представляющий вызов заданной функции при остановке входного отправителя, если получен сигнал «остановлено»
(объект-точка настройки)
execution::let_value
(C++26)
возвращает отправитель, представляющий узел, связанный с входным отправителем, который при запуске вызывает заданную функцию с переданными входным отправителем значениями в качестве аргументов
(объект-точка настройки)
execution::let_error
(C++26)
возвращает отправитель, представляющий узел, связанный с входным отправителем, который при возникновении ошибки вызывает заданную функцию с ошибкой входного отправителя
(объект-точка настройки)
execution::let_stopped
(C++26)
возвращает отправитель, представляющий узел, связанный с входным отправителем, который вызывает заданную функцию с токеном остановки входного отправителя при получении сигнала «остановлено»
(объект-точка настройки)
execution::bulkexecution::bulk_chunkedexecution::bulk_unchunked
(C++26)
создаёт многократно вызываемый отправитель, который вызывает функцию для каждого индекса заданной формы вместе со значениями, переданными входным отправителем. Отправитель завершается после завершения всех вызовов или при возникновении ошибки
(объект-точка настройки)
execution::when_all
(C++26)
преобразует несколько входных отправителей в отправитель, который завершается после завершения всех входных отправителей
(объект-точка настройки)
execution::when_all_with_variant
(C++26)
преобразует несколько входных отправителей, каждый из которых может иметь несколько сигнатур завершения, в отправитель, который завершается после завершения всех входных отправителей
(объект-точка настройки)
execution::into_variant
(C++26)
возвращает отправитель, передающий вариант кортежей для всех возможных наборов типов, передаваемых входным отправителем
(объект-точка настройки)
execution::stopped_as_optional
(C++26)
возвращает отправитель, который преобразует канал значений в std::optional<std::decay_t<T>>, а канал остановки — в std::nullopt
(объект-точка настройки)
execution::stopped_as_error
(C++26)
возвращает отправитель, который преобразует канал остановки в ошибку
(объект-точка настройки)
execution::associate
(C++26)
пытается связать отправитель с асинхронной областью, чтобы область могла отслеживать время жизни любых асинхронных операций, созданных с помощью этого отправителя
(объект-точка настройки)
execution::spawn_future
(C++26)
пытается связать заданный входной отправитель с асинхронной областью и в случае успеха немедленно запускает входной отправитель; возвращаемое значение — отправитель, который при соединении и запуске завершается результатом немедленно запущенного входного отправителя либо значением set_stopped, если входной отправитель не был запущен
(объект-точка настройки)

Потребители отправителей

Потребитель отправителя — это алгоритм, который принимает один или несколько отправителей в качестве параметров и не возвращает отправитель.

Определено в заголовочном файле <execution>
Определено в пространстве имён std::this_thread
this_thread::sync_wait
(C++26)
блокирует текущий поток до завершения заданного отправителя и возвращает результат его асинхронного выполнения
(объект-точка настройки)
this_thread::sync_wait_with_variant
(C++26)
блокирует текущий поток до завершения заданного отправителя, который может иметь несколько сигнатур завершения, и возвращает результат его асинхронного выполнения
(объект-точка настройки)
Определено в пространстве имён std::execution
execution::spawn
(C++26)
немедленно запускает заданный отправитель в асинхронной области и сразу возвращает управление, не дожидаясь его завершения
(объект-точка настройки)

Пример

Версия этого примера доступна на сайте godbolt.org, где используется stdexec — экспериментальная эталонная реализация std::execution.

#include <cstdio>
#include <execution>
#include <string>
#include <thread>
#include <utility>
using namespace std::literals;

int main()
{
    std::execution::run_loop loop;

    std::jthread worker([&](std::stop_token st)
    {
        std::stop_callback cb{st, [&]{ loop.finish(); }};
        loop.run();
    });
    
    std::execution::sender auto hello = std::execution::just("hello world"s);
    std::execution::sender auto print
        = std::move(hello)
        | std::execution::then([](std::string msg)
        {
            return std::puts(msg.c_str());
        });
    
    std::execution::scheduler auto io_thread = loop.get_scheduler();
    std::execution::sender auto work = std::execution::on(io_thread, std::move(print));
    
    auto [result] = std::this_thread::sync_wait(std::move(work)).value();
    
    return result;
}

Вывод:

hello world

См. также

async
(C++11)
асинхронно выполняет функцию (возможно, в новом потоке) и возвращает std::future, в котором будет храниться результат
(шаблон функции)

Внешние ссылки

1. NVIDIA/stdexec — эталонная реализация на github.com
2. bemanproject/execution — ещё одна эталонная реализация на github.com
3. Эрик Ниблер, 2024 г. — Для чего вообще нужны отправители?

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/execution

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API