std:: async
|
Definiert im Header
<future>
|
||
|
template
<
class
F,
class
...
Args
>
std:: future < /* siehe unten */ > async ( F && f, Args && ... args ) ; |
(1) | (seit C++11) |
|
template
<
class
F,
class
...
Args
>
std::
future
<
/* siehe unten */
>
async
(
std::
launch
policy,
|
(2) | (seit C++11) |
Die Funktionsvorlage
std::async
führt die Funktion
f
asynchron aus (möglicherweise in einem separaten Thread, der Teil eines Thread-Pools sein könnte) und gibt ein
std::future
zurück, das schließlich das Ergebnis dieses Funktionsaufrufs enthalten wird.
Der Rückgabetyp von
std::async
ist
std::
future
<
V
>
, wobei
V
Folgendes ist:
|
typename
std::
result_of
<
typename
std::
decay
<
F
>
::
type
(
|
(bis C++17) |
|
std:: invoke_result_t < std:: decay_t < F > , std:: decay_t < Args > ... > . |
(seit C++17) |
|
Wenn eine der folgenden Bedingungen erfüllt ist, ist das Programm fehlerhaft:
|
(bis C++20) |
|
Wenn eines der folgenden false ist, ist das Programm fehlerhaft:
|
(seit C++20) |
Der Aufruf von
std::async
synchronisiert mit
dem Aufruf von
f
, und der Abschluss von
f
ist
sequenziert vor
dem Bereitstellen des gemeinsamen Zustands.
Inhaltsverzeichnis |
Parameter
| f | - | Callable aufzurufendes Objekt |
| args | - | an f zu übergebende Parameter |
| policy | - | Bitmaskenwert, bei dem einzelne Bits die erlaubten Ausführungsmethoden steuern |
Rückgabewert
std::future
, das sich auf den gemeinsam genutzten Zustand bezieht, der durch diesen Aufruf von
std::async
erstellt wurde.
Ausführungsrichtlinien
Asynchrone Aufrufe
Wenn das
async
-Flag gesetzt ist, d.h.
(
policy
&
std::
launch
::
async
)
!
=
0
, dann ruft
std::async
auf
|
INVOKE
(
decay-copy
(
std::
forward
<
F
>
(
f
)
)
,
|
(bis C++23) |
|
std::
invoke
(
auto
(
std::
forward
<
F
>
(
f
)
)
,
|
(seit C++23) |
als ob in einem neuen Ausführungsstrang, dargestellt durch ein std::thread Objekt.
|
Die Aufrufe von decay-copy werden im aktuellen Thread ausgewertet. |
(bis C++23) |
|
Die durch auto erzeugten Werte werden materialisiert im aktuellen Thread. |
(seit C++23) |
Wenn die Funktion
f
einen Wert zurückgibt oder eine Ausnahme wirft, wird dies im gemeinsamen Zustand gespeichert, der über das
std::future
zugänglich ist, das
std::async
an den Aufrufer zurückgibt.
Verzögerter Aufruf
Wenn das
deferred
-Flag gesetzt ist (d.h.
(
policy
&
std::
launch
::
deferred
)
!
=
0
), dann speichert
std::async
|
decay-copy ( std:: forward < F > ( f ) ) und decay-copy ( std:: forward < Args > ( args ) ) ... im gemeinsamen Zustand. |
(bis C++23) |
|
auto ( std:: forward < F > ( f ) ) und auto ( std:: forward < Args > ( args ) ) ... im gemeinsamen Zustand. |
(seit C++23) |
Lazy evaluation wird durchgeführt:
-
Der erste Aufruf einer nicht zeitgesteuerten Wartefunktion auf dem
std::future
, das
std::asyncan den Aufrufer zurückgegeben hat, wird INVOKE ( std :: move ( g ) , std :: move ( xyz ) ) in dem Thread auswerten, der die Wartefunktion aufgerufen hat (dies muss nicht der Thread sein, der ursprünglichstd::asyncaufgerufen hat), wobei
|
(bis C++23) |
|
(seit C++23) |
- Das Ergebnis oder die Ausnahme wird in den gemeinsam genutzten Zustand platziert, der mit dem zurückgegebenen std::future assoziiert ist, und erst dann wird er bereit gemacht. Alle weiteren Zugriffe auf dasselbe std::future geben das Ergebnis sofort zurück.
Weitere Richtlinien
Wenn weder std::launch::async noch std::launch::deferred noch ein implementierungsdefiniertes Policy-Flag in policy gesetzt ist, ist das Verhalten undefiniert.
Richtlinienauswahl
Wenn mehr als ein Flag gesetzt ist, ist implementierungsdefiniert, welche Richtlinie ausgewählt wird. Für die Standardeinstellung (sowohl das std::launch::async - als auch das std::launch::deferred -Flag sind in policy gesetzt) empfiehlt der Standard (verpflichtet aber nicht), verfügbare Parallelität zu nutzen und zusätzliche Aufgaben zurückzustellen.
Wenn die std::launch::async -Richtlinie gewählt wird,
-
Ein Aufruf einer wartenden Funktion auf einem asynchronen Rückgabeobjekt, das den durch diesen
std::async-Aufruf erzeugten gemeinsamen Zustand teilt, blockiert bis der zugehörige Thread abgeschlossen ist (als wäre er gejoined) oder ein Timeout eintritt; und - der Abschluss des zugehörigen Threads synchronizes-with der erfolgreichen Rückkehr der ersten Funktion, die auf den gemeinsamen Zustand wartet, oder mit der Rückkehr der letzten Funktion, die den gemeinsamen Zustand freigibt, je nachdem, was zuerst eintritt.
Ausnahmen
Wirft
- std::bad_alloc , falls der Speicher für die internen Datenstrukturen nicht alloziert werden kann, oder
-
std::system_error
mit Fehlerzustand
std::errc::resource_unavailable_try_again
, falls
policy
==
std::
launch
::
async
und die Implementierung keinen neuen Thread starten kann.
- Falls policy gleich std:: launch :: async | std:: launch :: deferred ist oder zusätzliche Bits gesetzt sind, wird in diesem Fall auf verzögerte Ausführung oder die implementierungsdefinierten Richtlinien zurückgegriffen.
Hinweise
Die Implementierung kann das Verhalten der ersten Überladung von
std::async
erweitern, indem zusätzliche (implementierungsdefinierte) Bits in der Standard-Startrichtlinie aktiviert werden.
Beispiele für implementierungsdefinierte Startrichtlinien sind die Sync-Richtlinie (sofortige Ausführung, innerhalb des
std::async
-Aufrufs) und die Task-Richtlinie (ähnlich wie
std::async
, aber Thread-Lokale werden nicht bereinigt)
Wenn das
std::future
von
std::async
nicht verschoben oder an eine Referenz gebunden wird, blockiert der Destruktor des
std::future
am Ende des vollständigen Ausdrucks, bis der asynchrone Vorgang abgeschlossen ist, was Code wie den folgenden im Wesentlichen synchron macht:
std::async(std::launch::async, []{ f(); }); // Destruktor des Temporärs wartet auf f() std::async(std::launch::async, []{ g(); }); // startet erst nach Abschluss von f()
Beachten Sie, dass die Destruktoren von
std::future
s, die auf andere Weise als durch einen Aufruf von
std::async
erhalten wurden, niemals blockieren.
Beispiel
#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; // Ruft (&x)->foo(42, "Hello") mit Standard-Policy auf: // kann "Hello 42" parallel ausgeben oder Ausführung verzögern auto a1 = std::async(&X::foo, &x, 42, "Hello"); // Ruft x.bar("world!") mit verzögerter Policy auf // gibt "world!" aus wenn a2.get() oder a2.wait() aufgerufen wird auto a2 = std::async(std::launch::deferred, &X::bar, x, "world!"); // Ruft X()(43); mit Async-Policy auf // gibt "43" parallel aus auto a3 = std::async(std::launch::async, X(), 43); a2.wait(); // gibt "world!" aus std::cout << a3.get() << '\n'; // gibt "53" aus } // falls a1 an dieser Stelle noch nicht fertig ist, gibt Destruktor von a1 hier "Hello 42" aus
Mögliche Ausgabe:
The sum is 10000 43 world! 53 Hello 42
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| LWG 2021 | C++11 |
Rückgabetyp falsch und Wertkategorie
der Argumente im verzögerten Fall unklar |
Rückgabetyp korrigiert und
klargestellt, dass Rvalues verwendet werden |
| LWG 2078 | C++11 |
Es war unklar, ob
std::system_error
geworfen werden darf, wenn policy andere Startrichtlinien neben std::launch::async spezifiziert |
Kann nur geworfen werden, wenn
policy == std:: launch :: async |
| LWG 2100 | C++11 |
Zeitgesteuerte Wartefunktionen konnten nicht timeouten
wenn std::launch::async -Richtlinie verwendet wird |
Erlaubt |
| LWG 2120 | C++11 |
Das Verhalten war unklar, wenn keine Standard-
oder implementierungsdefinierte Richtlinie gesetzt ist |
Das Verhalten ist
in diesem Fall undefiniert |
| LWG 2186 | C++11 |
Es war unklar, wie der zurückgegebene Wert und die
bei der verzögerten Auswertung geworfene Exception behandelt werden |
Sie werden im
gemeinsamen Zustand gespeichert |
| LWG 2752 | C++11 |
std::async
könnte
std::bad_alloc
nicht werfen, wenn der
Speicher für die internen Datenstrukturen nicht allokiert werden kann |
Wirft |
| LWG 3476 | C++20 |
(Die zerfallenen Typen von)
F
und den Argumenttypen
wurden direkt als beweglich konstruierbar vorausgesetzt |
Diese Anforderungen entfernt [1] |
- ↑ Die Move-Konstruierbarkeit ist bereits indirekt durch std::is_constructible_v vorausgesetzt.
Siehe auch
|
(C++11)
|
wartet auf einen asynchron gesetzten Wert
(Klassentemplate) |
|
C++-Dokumentation
für
Execution Support Library
|
|