2015-05-29 9 views
5

Ich habe den folgenden Code geschrieben, um std::async() auf Funktionen void mit GCC 4.8.2 auf Ubuntu zu testen.Wird std :: async garantiert für Funktionen aufgerufen, die void zurückgeben?

#include <future> 
#include <iostream> 

void functionTBC() 
{ 
    std::cerr << "Print here\n"; 
} 

int main(void) 
{ 
#ifdef USE_ASYNC 
    auto i = std::async(std::launch::async, functionTBC); 
#else 
    auto i = std::async(std::launch::deferred, functionTBC); 
#endif 
    //i.get(); 
    return 0; 
} 

Wenn i.get(); unkommentiert ist, wird die Meldung "Print here" immer vorhanden ist; Wenn jedoch i.get(); auskommentiert ist, existiert "Print here", wenn und nur wenn USE_ASYNC definiert ist (dh std::launch::async führt immer zur Nachricht ausgedruckt, während std::launch::deferred niemals).

Ist dieses garantierte Verhalten? Wie kann man sicherstellen, dass der asynchrone Aufruf void ausgeführt wird?

+4

Wenn Sie nach einem verzögerten Start fragen und niemals .get in dieser Zukunft aufrufen, wird Ihre Funktion niemals ausgeführt. Dies hat nichts mit der Funktion zu tun, die void oder irgendeinen anderen Typ zurückgibt. – sbabbi

Antwort

7

std::launch::deferred bedeutet "nicht ausführen, bis ich .wait() oder .get()".

Wie Sie nie .get() oder .wait() Ed, es lief nie.

void hat nichts damit zu tun.

Für std::launch::async, der Standard besagt, dass die zurück Zukunft destructor (~future) blockiert, bis die Aufgabe abgeschlossen ist (dh hat eine implizites .wait()). Dies wird von MSVC absichtlich verletzt, weil sie mit dieser Designentscheidung nicht einverstanden waren, und sie kämpfen darum, den Standard zu ändern: In der Praxis bedeutet dies, dass Sie sich von std::launch::asyncfuture nicht verlassen können, wenn Sie zukunftssicher sein wollen dein Code.

Ohne implizite wait in ~future, wäre es unbestimmt, wenn es tatsächlich die Funktion aufgerufen, wenn main beendet. Es wäre entweder passiert oder nicht. Möglicherweise könnten Sie UB aufrufen, indem Sie noch aktive Threads am Ende von main haben.

Sie fragen sich vielleicht, welche Verwendung deferred hat: Sie können es verwenden, um eine Berechnung für faule Auswertung in die Warteschlange.

+0

Wenn ich einfach den Rückgabewert von 'std :: async()' lösche (entferne das 'auto i =' in meinem Snippet), wird die 'std :: launch :: deferred 'Version immer noch übersprungen. Verstößt dies nicht gegen '' ~ future' wird blockiert, bis die Aufgabe abgeschlossen ist? " – timrau

+0

"~ Zukunft wird blockiert, bis die Aufgabe abgeschlossen ist" gilt nicht in diesem Fall wegen std :: launch :: deferred. Ich schlage vor, dass Sie eine Kopie von Meyers "Effective Modern C++" abholen, siehe Punkt 38. – kfsone

+1

@timrau Der Hinweis zu '~ future'-Blockierung gilt nur, wenn Sie' std :: async (std :: launch :: async') Das Aufrufen von 'std :: async '(std :: launch :: async') ohne Speichern des Rückgabewerts führt dazu, dass die Anweisung am Ende der Anweisung gelöscht wird. Der Hauptthread blockiert also, bis die asynchrone Task in dieser Zeile * abgeschlossen ist. Speichern Sie es in 'auto i =' wird der Block am Ende des Bereichs auftreten.Move the Returned 'Future' zu ​​einem anderen' Future' wird den Block verschieben, bis die Zukunft, die den Zustand speichert, endgültig zerstört wird. – Yakk

Verwandte Themen