Библиотека управления выполнением (начиная с C++26)
Библиотека управления выполнением предоставляет среду для управления асинхронным выполнением на универсальных ресурсах выполнения.
Цель библиотеки — предоставить типы словаря для асинхронных операций и дать возможность простым и компонуемым способом строить графы выполнения задач.
Общие определения библиотеки
- Отправитель: описание асинхронной работы, предназначенной для выполнения. Создаёт состояние операции (см. ниже).
- Отправители асинхронно «отправляют» свои результаты слушателям, называемым «получателями» (см. ниже).
- Отправители можно объединять в графы задач с помощью универсальных алгоритмов.
-
Фабрики отправителей и адаптеры — универсальные алгоритмы, которые заключают распространённые асинхронные шаблоны в объекты, удовлетворяющие концепции
sender. - С отправителем связан «объект, поддерживающий запросы» (см. ниже), называемый атрибутами отправителя, который описывает различные характеристики отправителя и создаваемых им асинхронных операций.
- Получатель: обобщённый обратный вызов, который использует или «получает» асинхронные результаты, созданные отправителем.
- У получателей есть три различных «канала», по которым отправитель может передавать результаты: успешное завершение, ошибка и отмена, называемые соответственно «значением», «ошибкой» и «остановкой».
- Получатели предоставляют расширяемую среду выполнения: «объект, поддерживающий запросы» (см. ниже), который потребитель может использовать для настройки асинхронной операции.
- Состояние операции: объект, содержащий состояние, необходимое асинхронной операции.
- Отправитель и получатель связываются при передаче функции
std::execution::connect. - Результатом связывания отправителя и получателя является состояние операции.
- Работа не ставится в очередь на выполнение, пока для состояния операции не вызвана функция «
start». - После запуска время жизни состояния операции не может завершиться до окончания асинхронной операции, а его адрес должен оставаться неизменным.
- Агент выполнения: сущность, например поток, которая может выполнять работу параллельно с другими агентами выполнения.
- Реализации или пользователи могут вводить другие виды агентов, например процессы или задачи пула потоков.
- Ресурс выполнения: сущность программы, также называемая контекстом выполнения, которая управляет (возможно, динамическим) набором агентов выполнения.
- Текущий активный поток, предоставляемый системой пул потоков и использование API, связанного с внешним аппаратным ускорителем, — всё это примеры ресурсов выполнения.
- Планировщик: лёгкий дескриптор ресурса выполнения, предназначенный для планирования работы на этом ресурсе.
- Планировщик — это фабрика отправителя, который завершает работу с получателем от агента выполнения, принадлежащего ресурсу выполнения.
- Объект, поддерживающий запросы: доступная только для чтения коллекция пар «ключ/значение», в которой каждый ключ — объект точки настройки, называемый «объектом запроса».
- Запрос — это вызов объекта запроса, которому в качестве первого аргумента передаётся объект, поддерживающий запросы, а также (возможно, пустой) набор дополнительных аргументов. Запрос задаёт синтаксические и семантические требования к своим вызовам.
Утилиты библиотеки
Концепции
Планировщики
Определено в заголовке <execution> |
|
|---|---|
Определено в пространстве имён std::execution |
|
|
(C++26) | задаёт требования, которым должен соответствовать тип, являющийся планировщиком (концепция) |
Отправители
Определено в заголовке <execution> |
|
|---|---|
Определено в пространстве имён std::execution |
|
|
(C++26) | задаёт требования, которым должен соответствовать тип, являющийся отправителем (концепция) |
|
(C++26) | задаёт требования к отправителю, который может создавать асинхронные операции для заданного связанного типа среды (концепция) |
|
(C++26) | задаёт требования к типу отправителя, сигнатуры завершения которого невозможно определить независимо от его среды выполнения (концепция) |
Получатели
Определено в заголовке <execution> |
|
|---|---|
Определено в пространстве имён std::execution |
|
|
(C++26) | задаёт требования, которым должен соответствовать тип, являющийся получателем (концепция) |
|
(C++26) | задаёт требования к получателю, который можно восстановить по требованию по указателю на объект состояния операции, созданный при связывании получателя с отправителем (концепция) |
Состояния операций
Определено в заголовке <execution> |
|
|---|---|
Определено в пространстве имён std::execution |
|
|
(C++26) | задаёт требования, которым должен соответствовать тип, являющийся состоянием операции (концепция) |
Асинхронные области видимости
Определено в заголовке <execution> |
|
|---|---|
Определено в пространстве имён std::execution |
|
|
(C++26) | задаёт требования к дескриптору RAII, представляющему активную связь с асинхронной областью видимости (концепция) |
|
(C++26) | задаёт невладеющий дескриптор асинхронной области видимости, который ведёт себя как ссылка на асинхронную область видимости (концепция) |
Вспомогательные компоненты
Контексты выполнения
Определено в заголовке <execution> |
|
|---|---|
Определено в пространстве имён std::execution |
|
|
(C++26) | ресурс выполнения, содержащий потокобезопасную очередь задач MPSC и управляемый вручную цикл событий (класс) |
Домены выполнения
Определено в заголовке <execution> |
|
|---|---|
Определено в пространстве имён std::execution |
|
|
(C++26) | тип-тег домена выполнения по умолчанию, который выбирает преобразования на основе тега отправителя (класс) |
|
(C++26) | преобразует отправитель в новый отправитель в заданном домене выполнения (шаблон функции) |
|
(C++26) | использует отправитель с заданным тегом потребителя отправителя и набором аргументов и возвращает результат в заданном домене выполнения (шаблон функции) |
Гарантия продвижения вперёд
Определено в заголовке <execution> |
|
|---|---|
Определено в пространстве имён std::execution |
|
|
(C++26) | задаёт гарантию продвижения вперёд для агентов выполнения, созданных связанным ресурсом выполнения планировщика (перечисление) |
Среды
Определено в заголовке <execution> |
|
|---|---|
Определено в пространстве имён std::execution |
|
|
(C++26) | создаёт объект, поддерживающий запросы, из объекта запроса и значения (шаблон класса) |
|
(C++26) | объединяет несколько объектов, поддерживающих запросы, в один такой объект (шаблон класса) |
|
(C++26) | возвращает связанный объект, поддерживающий запросы, для заданного аргумента (объект точки настройки) |
Запросы
Определено в заголовке <execution> |
|
|---|---|
|
(C++26) | спрашивает у объекта запроса, следует ли передавать его через адаптеры объектов, поддерживающих запросы (объект точки настройки) |
|
(C++26) | запрашивает у объекта, поддерживающего запросы, связанный с ним распределитель памяти (объект точки настройки) |
|
(C++26) | запрашивает у объекта, поддерживающего запросы, связанный с ним токен остановки (объект точки настройки) |
|
(C++26) | запрашивает у объекта, поддерживающего запросы, связанный с ним тег домена выполнения (объект точки настройки) |
|
(C++26) | запрашивает домен завершения, связанный с тегом завершения из атрибутов отправителя (объект точки настройки) |
|
(C++26) | запрашивает у объекта, поддерживающего запросы, связанный с ним планировщик (объект точки настройки) |
|
(C++26) | запрашивает у среды получателя планировщик, в котором будет запущено состояние операции, созданное с этим получателем. (объект точки настройки) |
|
(C++26) | запрашивает у объекта, поддерживающего запросы, планировщик, которому можно делегировать работу для обеспечения делегирования продвижения вперёд (объект точки настройки) |
|
(C++26) | получает планировщик завершения, связанный с тегом завершения из атрибутов отправителя (объект точки настройки) |
|
(C++26) | запрашивает у планировщика его execution::forward_progress_guarantee(объект точки настройки) |
|
(C++26) | запрашивает у объекта, поддерживающего запросы, связанный с ним адаптер завершения для await (объект точки настройки) |
Сигнатуры завершения
Определено в заголовке <execution> |
|
|---|---|
Определено в пространстве имён std::execution |
|
|
(C++26) | тип, кодирующий набор сигнатур завершения (шаблон класса) |
|
(C++26) | получает сигнатуры завершения отправителя (объект точки настройки) |
|
(C++26) | получает тип тега отправителя (шаблон псевдонима) |
|
(C++26) | получает тип завершения значением отправителя (шаблон псевдонима) |
|
(C++26) | получает тип завершения ошибкой отправителя (шаблон псевдонима) |
|
(C++26) | определяет, поддерживает ли отправитель завершение остановкой (шаблон переменной) |
Утилиты корутин
Определено в заголовке <execution> |
|
|---|---|
Определено в пространстве имён std::execution |
|
|
(C++26) | преобразует выражение в объект, доступный для await, в рамках определённой корутины (объект точки настройки) |
|
(C++26) | при использовании в качестве базового класса типа promise корутины позволяет ожидать отправители в рамках этого типа корутины (шаблон класса) |
|
(C++26) | адаптирует отправитель так, чтобы он завершался в планировщике получателя. Если алгоритм определяет, что адаптированный отправитель уже завершается в нужном планировщике, он может избежать операции планирования (объект точки настройки) |
|
(C++26) | простой планировщик, который немедленно и синхронно завершает выполнение в потоке, вызывающем std::execution::start для состояния операции, созданного его отправителем (класс) |
|
(C++26) | представляет отправитель, который можно использовать в качестве возвращаемого типа функций-корутин (шаблон класса) |
|
(C++26) | предоставляет единообразный интерфейс со стиранием типа, позволяющий хранить, передавать и вызывать операции планирования для произвольных безошибочных планировщиков (класс) |
Асинхронные области видимости
Определено в заголовке <execution> |
|
|---|---|
Определено в пространстве имён std::execution |
|
|
(C++26) | лёгкая асинхронная область видимости со счётчиком ссылок. Отслеживает количество выполняющихся в данный момент асинхронных операций, динамически порождённых в этой области (класс) |
|
(C++26) | отличается от simple_counting_scope поддержкой отмены (класс) |
Параллельный планировщик
Определено в заголовочном файле <execution> |
|
|---|---|
Определено в пространстве имён std::execution |
|
|
(C++26) | представляет дескриптор общего глобального ресурса выполнения (например, системного пула потоков, предоставляемого ОС), оптимизированного для параллельного выполнения (класс) |
|
(C++26) | возвращает экземпляр parallel_scheduler, представляющий общий контекст параллельного выполнения в приложении. последовательные вызовы этой функции возвращают объекты планировщика, ссылающиеся на один и тот же базовый глобальный пул потоков (функция) |
Определено в пространстве имён std::execution::parallel_scheduler_replacement |
|
|
(C++26) | представляет получателя, который будет уведомлён реализациями parallel_scheduler_backend для запуска операций завершения (класс) |
|
(C++26) | используется для настроек bulk_chunked и bulk_unchunked, которые также будут получать уведомления от реализаций parallel_scheduler_backend, соответствующие различным итерациям (класс) |
|
(C++26) | служит абстрактным связующим звеном между пользовательским parallel_scheduler и внутренним ресурсом выполнения (например, системным пулом потоков, предоставляемым ОС) (класс) |
|
(C++26) | возвращает shared_ptr<parallel_scheduler_backend>, представляющий общий контекст параллельного выполнения в приложении. последовательные вызовы этой функции возвращают shared_ptr, указывающие на один и тот же объект parallel_scheduler_backend (функция) |
Основные операции
Состояние операции
Определено в заголовочном файле <execution> |
|
|---|---|
Определено в пространстве имён std::execution |
|
|
(C++26) | соединяет sender с receiver(объект-точка настройки) |
|
(C++26) | запускает асинхронную операцию, связанную с объектом operation_state(объект-точка настройки) |
Функции завершения
Эти функции вызываются отправителями, чтобы сообщить получателям о завершении работы.
Определено в заголовочном файле <execution> |
|
|---|---|
Определено в пространстве имён std::execution |
|
|
(C++26) | функция завершения со значением, указывающая на успешное завершение (объект-точка настройки) |
|
(C++26) | функция завершения с ошибкой, указывающая, что при вычислении или планировании произошла ошибка (объект-точка настройки) |
|
(C++26) | функция завершения с остановкой, указывающая, что операция закончилась до достижения успеха или ошибки (объект-точка настройки) |
Алгоритмы отправителей
Фабрики отправителей
Фабрика отправителей — это функция, возвращающая отправитель, параметры которой имеют типы, удовлетворяющие концепту sender false.
К фабрикам отправителей относятся:
Определено в заголовочном файле <execution> |
|
|---|---|
Определено в пространстве имён std::execution |
|
|
(C++26) | принимает произвольное количество аргументов и возвращает отправитель, который при соединении и запуске завершается синхронно, передавая аргументы функции завершения со значением получателя (объект-точка настройки) |
|
(C++26) | принимает один аргумент и возвращает отправитель, который при соединении и запуске завершается синхронно, передавая аргумент функции завершения с ошибкой получателя (объект-точка настройки) |
|
(C++26) | создаёт отправитель, который немедленно завершается вызовом set_stopped своего получателя(объект-точка настройки) |
|
(C++26) | создаёт отправитель, который запрашивает среду, связанную с его получателем (объект-точка настройки) |
|
(C++26) | подготавливает граф задач к выполнению с помощью заданного планировщика (объект-точка настройки) |
Адаптеры отправителей, объединяемые в конвейер
Определено в заголовочном файле <execution> |
|
|---|---|
Определено в пространстве имён std::execution |
|
|
(C++26) | вспомогательный базовый шаблон класса для определения объекта-замыкания адаптера отправителя, объединяемого в конвейер (шаблон класса) |
Адаптеры отправителей
Адаптер отправителя — это функция, возвращающая отправитель, среди параметров которой есть как минимум один параметр с типом, удовлетворяющим концепту sender, причём возвращаемый отправитель является родительским отправителем аргументов-отправителей этой функции-адаптера.
К адаптерам отправителей относятся:
Определено в заголовочном файле <execution> |
|
|---|---|
Определено в пространстве имён std::execution |
|
|
(C++26) | внедряет значения в среду, доступную заданному отправителю, — переопределяя или дополняя сведения, предоставляемые конечным получателем (объект-точка настройки) |
|
(C++26) | защищает заданный отправитель от внешних запросов на отмену, обеспечивая непрерывное выполнение критической задачи до завершения (объект-точка настройки) |
|
(C++26) | преобразует заданный отправитель в отправитель, который запускает выполнение с использованием ресурса выполнения заданного планировщика (объект-точка настройки) |
|
(C++26) | преобразует заданный отправитель в отправитель, который завершается с использованием ресурса выполнения заданного планировщика (объект-точка настройки) |
|
(C++26) | преобразует заданный отправитель, перенося выполнение на ресурс выполнения заданного планировщика, где выполняется отправитель или продолжение, а затем возвращая выполнение исходному ресурсу (объект-точка настройки) |
|
(C++26) | планирует выполнение работы, зависящей от завершения заданного отправителя, на ресурсе выполнения заданного планировщика (объект-точка настройки) |
|
(C++26) | добавляет в граф задач после входного отправителя узел, представляющий вызов заданной функции с переданными входным отправителем значениями в качестве аргументов (объект-точка настройки) |
|
(C++26) | добавляет в граф задач после входного отправителя узел, представляющий вызов заданной функции с ошибкой, переданной входным отправителем, если произошла ошибка (объект-точка настройки) |
|
(C++26) | добавляет в граф задач после входного отправителя узел, представляющий вызов заданной функции при остановке входного отправителя, если получен сигнал «остановлено» (объект-точка настройки) |
|
(C++26) | возвращает отправитель, представляющий узел, связанный с входным отправителем, который при запуске вызывает заданную функцию с переданными входным отправителем значениями в качестве аргументов (объект-точка настройки) |
|
(C++26) | возвращает отправитель, представляющий узел, связанный с входным отправителем, который при возникновении ошибки вызывает заданную функцию с ошибкой входного отправителя (объект-точка настройки) |
|
(C++26) | возвращает отправитель, представляющий узел, связанный с входным отправителем, который вызывает заданную функцию с токеном остановки входного отправителя при получении сигнала «остановлено» (объект-точка настройки) |
|
(C++26) | создаёт многократно вызываемый отправитель, который вызывает функцию для каждого индекса заданной формы вместе со значениями, переданными входным отправителем. Отправитель завершается после завершения всех вызовов или при возникновении ошибки (объект-точка настройки) |
|
(C++26) | преобразует несколько входных отправителей в отправитель, который завершается после завершения всех входных отправителей (объект-точка настройки) |
|
(C++26) | преобразует несколько входных отправителей, каждый из которых может иметь несколько сигнатур завершения, в отправитель, который завершается после завершения всех входных отправителей (объект-точка настройки) |
|
(C++26) | возвращает отправитель, передающий вариант кортежей для всех возможных наборов типов, передаваемых входным отправителем (объект-точка настройки) |
|
(C++26) | возвращает отправитель, который преобразует канал значений в std::optional<std::decay_t<T>>, а канал остановки — в std::nullopt (объект-точка настройки) |
|
(C++26) | возвращает отправитель, который преобразует канал остановки в ошибку (объект-точка настройки) |
|
(C++26) | пытается связать отправитель с асинхронной областью, чтобы область могла отслеживать время жизни любых асинхронных операций, созданных с помощью этого отправителя (объект-точка настройки) |
|
(C++26) | пытается связать заданный входной отправитель с асинхронной областью и в случае успеха немедленно запускает входной отправитель; возвращаемое значение — отправитель, который при соединении и запуске завершается результатом немедленно запущенного входного отправителя либо значением set_stopped, если входной отправитель не был запущен(объект-точка настройки) |
Потребители отправителей
Потребитель отправителя — это алгоритм, который принимает один или несколько отправителей в качестве параметров и не возвращает отправитель.
Определено в заголовочном файле <execution> |
|
|---|---|
Определено в пространстве имён std::this_thread |
|
|
(C++26) | блокирует текущий поток до завершения заданного отправителя и возвращает результат его асинхронного выполнения (объект-точка настройки) |
|
(C++26) | блокирует текущий поток до завершения заданного отправителя, который может иметь несколько сигнатур завершения, и возвращает результат его асинхронного выполнения (объект-точка настройки) |
Определено в пространстве имён std::execution |
|
|
(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
См. также
|
(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