Namespaces
Variants

std:: async

From cppreference.net
Concurrency support library
Threads
(C++11)
(C++20)
this_thread namespace
(C++11)
(C++11)
Cooperative cancellation
Mutual exclusion
Generic lock management
Condition variables
(C++11)
Semaphores
Latches and Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
async
(C++11)
Safe reclamation
Hazard pointers
Atomic types
(C++11)
(C++20)
Initialization of atomic types
(C++11) (deprecated in C++20)
(C++11) (deprecated in C++20)
Memory ordering
(C++11) (deprecated in C++26)
Free functions for atomic operations
Free functions for atomic flags
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,

F && f, Args && ... args ) ;
(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.

1) Verhält sich so, als ob (2) aufgerufen würde mit policy als std:: launch :: async | std:: launch :: deferred .
2) Ruft eine Funktion f mit Argumenten args gemäß einer spezifischen Startrichtlinie policy auf (siehe unten ).

Der Rückgabetyp von std::async ist std:: future < V > , wobei V Folgendes ist:

typename std:: result_of < typename std:: decay < F > :: type (
typename std:: decay < Args > :: type ... ) > :: 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 ) ) ,
decay-copy ( std:: forward < Args > ( args ) ) ... )

(bis C++23)

std:: invoke ( auto ( std:: forward < F > ( f ) ) ,
auto ( std:: forward < Args > ( args ) ) ... )

(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::async an 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ünglich std::async aufgerufen hat), wobei
(bis C++23)
  • g ist der gespeicherte Wert von auto ( std:: forward < F > ( f ) ) und
  • xyz ist die gespeicherte Kopie von auto ( std:: forward < Args > ( args ) ) ... .
(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

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]
  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