std::async
Определено в заголовке <future> | ||
|---|---|---|
| (1) | ||
template< class Function, class... Args >
std::future<typename std::result_of<typename std::decay<Function>::type(
typename std::decay<Args>::type...)>::type>
async( Function&& f, Args&&... args ); |
(с C++11) (до C++17) | |
template< class Function, class... Args >
std::future<std::invoke_result_t<std::decay_t<Function>,
std::decay_t<Args>...>>
async( Function&& f, Args&&... args );
| (с C++17) (до C++20) | |
template< class Function, class... Args >
[[nodiscard]] std::future<std::invoke_result_t<std::decay_t<Function>,
std::decay_t<Args>...>>
async( Function&& f, Args&&... args );
| (с C++20) | |
| (2) | ||
template< class Function, class... Args >
std::future<typename std::result_of<typename std::decay<Function>::type(
typename std::decay<Args>::type...)>::type>
async( std::launch policy, Function&& f, Args&&... args ); |
(с C++11) (до C++17) | |
template< class Function, class... Args >
std::future<std::invoke_result_t<std::decay_t<Function>,
std::decay_t<Args>...>>
async( std::launch policy, Function&& f, Args&&... args );
| (с C++17) (до C++20) | |
template< class Function, class... Args >
[[nodiscard]] std::future<std::invoke_result_t<std::decay_t<Function>,
std::decay_t<Args>...>>
async( std::launch policy, Function&& f, Args&&... args );
| (с C++20) |
Шаблон функции std::async выполняет функцию f асинхронно (возможно, в отдельном потоке, который может быть частью пула потоков) и возвращает std::future, который в конечном итоге будет содержать результат этого вызова функции.
policy в качестве std::launch::async | std::launch::deferred. f с аргументами args в соответствии с определённой политикой запуска policy (см. ниже).Вызов std::async синхронизируется (как определено в std::memory_order) с вызовом f, и завершение f предшествует подготовке общего состояния.
| Если | (до C++20) |
| Программа некорректна, если
| (с C++20) |
Параметры
| f | - | Объект Callable для вызова | ||||||
| args... | - | параметры для передачи в f |
||||||
| policy | - | значение битовой маски, где отдельные биты управляют допустимыми методами выполнения
|
Возвращаемое значение
std::future, ссылающийся на общее состояние, созданное этим вызовом std::async.
Политики запуска
Асинхронное выполнение
Если флаг async установлен (т.е. (policy & std::launch::async) != 0), то
|
| (до C++23) |
|
| (с C++23) |
Вызовы decay-copy оцениваются(до C++23)Значения, создаваемые auto,материализуются(с C++23) в текущем потоке. Если функция f возвращает значение или вызывает исключение, оно сохраняется в общем состоянии, доступном через std::future, которое std::async возвращает вызывающей стороне.
Отложенное выполнение
Если флаг deferred установлен (т.е. (policy & std::launch::deferred) != 0), то std::async сохраняет decay-copy(std::forward<F>(f)) и decay-copy(std::forward<Args>(args))...(до C++23)auto(std::forward<F>(f)) и auto(std::forward<Args>(args))...(с C++23) в общем состоянии.
Выполняется ленивая оценка:
- Первый вызов функции ожидания без таймаута для
std::future, возвращённойstd::asyncвызывающей стороне, вычислитINVOKE(std::move(g), std::move(xyz))в текущем потоке (который не обязательно является потоком, первоначально вызвавшимstd::async), где -
g— хранимое значениеdecay-copy(std::forward<F>(f))(до C++23)auto(std::forward<F>(f))(с C++23) и -
xyz— сохранённая копияdecay-copy(std::forward<Args>(args))...(до C++23)auto(std::forward<Args>(args))...(с C++23). - Результат или исключение помещаются в общее состояние, связанное с возвращённым
std::future, и только после этого делаются доступными. Все последующие обращения к тому жеstd::futureвернут результат немедленно.
Другие политики
Если ни std::launch::async, ни std::launch::deferred, ни какая-либо реализационно-зависимая политика флага не установлена в policy, поведение не определено.
Выбор политики
Если установлено более одного флага, то выбор политики определяется реализацией. Для по умолчанию (когда оба флага std::launch::async и std::launch::deferred установлены в policy стандарт рекомендует (но не требует), использовать доступную конкурецию и откладывать любые дополнительные задачи.
Если выбрана политика std::launch::async,
- вызов функции ожидания на объекте асинхронного возврата, который разделяет общее состояние, созданное этим вызовом
std::asyncблокируется, пока связанный поток не завершится (как если бы он был присоединён), или пока не истечёт время ожидания; и - завершение связанного потока синхронизируется с успешным возвратом из первой функции, ожидающей общего состояния, или с возвратом последней функции, освобождающей общее состояние, в зависимости от того, что произойдёт раньше.
Исключения
Бросает
-
std::bad_alloc, если память для внутренних структур данных не может быть выделена, или -
std::system_errorс кодом ошибкиstd::errc::resource_unavailable_try_again, еслиpolicy == std::launch::asyncи реализация не могут запустить новый поток.- Если
policyравноstd::launch::async | std::launch::deferredили имеет установленные дополнительные биты, происходит откат к отложенному выполнению или реализационно-зависимым политикам в этом случае.
- Если
Примечания
Реализация может расширить поведение первого перегрузки std::async путём включения дополнительных (реализационно-зависимых) битов в политику запуска по умолчанию.
Примеры реализационно-зависимых политик запуска — политика синхронного запуска (выполнение немедленно, в рамках вызова std::async ) и политика задания (похожая на std::async, но переменные состояния потоков не очищаются).
Если std::future , полученный от std::async не перемещается или не привязывается к ссылке, деструктор std::future будет блокироваться в конце полного выражения, пока асинхронная операция не завершится, по существу делая код, подобный следующему, синхронным:
std::async(std::launch::async, []{ f(); }); // temporary's dtor waits for f()
std::async(std::launch::async, []{ g(); }); // does not start until f() completesОбратите внимание, что деструкторы std::future , полученные другими способами, кроме вызова std::async, никогда не блокируются.
Пример
#include <algorithm>
#include <future>
#include <iostream>
#include <mutex>
#include <numeric>
#include <string>
#include <vector>
std::mutex m;
struct X
{
void foo(int i, const std::string& str)
{
std::lock_guard<std::mutex> lk(m);
std::cout << str << ' ' << i << '\n';
}
void bar(const std::string& str)
{
std::lock_guard<std::mutex> lk(m);
std::cout << str << '\n';
}
int operator()(int i)
{
std::lock_guard<std::mutex> lk(m);
std::cout << i << '\n';
return i + 10;
}
};
template<typename RandomIt>
int parallel_sum(RandomIt beg, RandomIt end)
{
auto len = end - beg;
if (len < 1000)
return std::accumulate(beg, end, 0);
RandomIt mid = beg + len / 2;
auto handle = std::async(std::launch::async,
parallel_sum<RandomIt>, mid, end);
int sum = parallel_sum(beg, mid);
return sum + handle.get();
}
int main()
{
std::vector<int> v(10000, 1);
std::cout << "The sum is " << parallel_sum(v.begin(), v.end()) << '\n';
X x;
// Calls (&x)->foo(42, "Hello") with default policy:
// may print "Hello 42" concurrently or defer execution
auto a1 = std::async(&X::foo, &x, 42, "Hello");
// Calls x.bar("world!") with deferred policy
// prints "world!" when a2.get() or a2.wait() is called
auto a2 = std::async(std::launch::deferred, &X::bar, x, "world!");
// Calls X()(43); with async policy
// prints "43" concurrently
auto a3 = std::async(std::launch::async, X(), 43);
a2.wait(); // prints "world!"
std::cout << a3.get() << '\n'; // prints "53"
} // if a1 is not done at this point, destructor of a1 prints "Hello 42" hereВозможный вывод:
The sum is 10000 43 world! 53 Hello 42
Отчёты о дефектах
Следующие изменения поведения были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применяется к | Поведение, опубликованное в документе | Правильное поведение |
|---|---|---|---|
| LWG 2021 | C++11 | неверный тип возвращаемого значения и категория значения аргументов неясны в отложенном случае | исправленный тип возвращаемого значения и уточнено, что используются rvalues |
| LWG 2078 | C++11 | неясно, может ли быть брошено исключение std::system_errorесли policy задаёт другиеполитики запуска помимо std::launch::async | исключение может быть брошено только в случаеpolicy == std::launch::async |
| LWG 2100 | C++11 | функции таймаута ожидания не могли завершиться по таймауту, если использовалась политика std::launch::async | разрешено |
| LWG 2120 | C++11 | поведение было неясно, если не задана стандартная или определённая реализацией политика | в этом случае поведение является неопределённым |
| LWG 2752 | C++11 |
std::async возможно не бросит std::bad_alloc если памятьдля внутренних структур данных не может быть выделена | бросает |
| LWG 3476 | C++11 |
Function и Args... должны были быть MoveConstructibleв то время как никаких дополнительных движений не указано | требования удалены |
См. также
|
(C++11) | ожидание значения, которое устанавливается асинхронно (шаблон класса) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/thread/async