Holen Sie sich den Status einer std :: future

83

Ist es möglich zu überprüfen, ob a std::futurefertig ist oder nicht? Soweit ich das beurteilen kann, besteht der einzige Weg darin, wait_formit einer Dauer von Null anzurufen und zu überprüfen, ob der Status lautet readyoder nicht, aber gibt es einen besseren Weg?

David Brown
quelle
10
@CatPlusPlus Wenn ich mich nicht irre, wird validnur geprüft, ob die Zukunft einen gemeinsamen Status hat (dh sie kehrt zurück, truebis getsie für die Zukunft aufgerufen wird).
David Brown
Wenn Sie getalso aufgerufen wurden und den gespeicherten Wert zurückgeben, möchten Sie trotzdem true? (Ich bin nicht sicher, warum dies nützlich wäre, da Sie den Wert nur einmal erhalten können.)
James McNellis
@JamesMcNellis Vielleicht verstehe ich Futures falsch oder missbrauche sie, aber ich möchte wissen, ob der Thread (oder was auch immer die Berechnung durchführt) beendet ist oder nicht. Das Äquivalent von Qt ist im QFuture::isFinishedGrunde.
David Brown
1
Ein Warten mit einer Zeitüberschreitung von Null ist, wie die meisten APIs auf vielen Plattformen mit einem solchen Konzept umgehen ... So sehr, dass ich es als "Standard" -Methode für die Annäherung an das Konzept betrachten würde. Dies macht mich ein bisschen verwirrt über die Vorstellung von "einem besseren Weg" ...
Asveikau
16
@asveikau Mir war nicht bewusst, dass dies eine Standardpraxis war. Es fühlt sich einfach seltsam an, eine Wartefunktion aufzurufen, wenn ich nicht warten möchte.
David Brown

Antworten:

85

Sie haben Recht, und abgesehen davon, dass Sie wait_untilmit einer Zeit in der Vergangenheit anrufen (was gleichwertig ist), gibt es keinen besseren Weg.

Sie können jederzeit einen kleinen Wrapper schreiben, wenn Sie eine bequemere Syntax wünschen:

template<typename R>
  bool is_ready(std::future<R> const& f)
  { return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready; }

Hinweis: Wenn die Funktion zurückgestellt wird, wird dies niemals true zurückgeben. Daher ist es wahrscheinlich besser, wait_fordirekt zu prüfen, ob Sie die zurückgestellte Aufgabe nach Ablauf einer bestimmten Zeit oder bei geringer Systemlast synchron ausführen möchten.

Jonathan Wakely
quelle
2
wait_for mutiert die Zukunft nicht, sodass der Parameter als const deklariert werden kann.
Jens Åkerblom
7
Überprüfen Sie zuerst valid (), um Laufzeitfehler zu vermeiden, wenn get bereits aufgerufen wurde oder die Zukunft nie initialisiert wurde.
Jeremy Sorensen
5
Wird wait_for (chrono :: Sekunden (0)) garantiert sofort zurückgegeben oder kann bei einigen Implementierungen die Steuerung des Threads für einige Millisekunden erfolgen? Dies wäre sehr wichtig zu wissen, da ein paar Millisekunden viel Zeit für das Codieren eines Spiels sind ...
kynnysmatto
9
@kynnysmatto, bei einigen Implementierungen erhält es eine Mutex-Sperre, um den Status der Zukunft sicher zu überprüfen. Wenn diese Sperre also angefochten wird (weil ein anderer Thread den Status bereit macht oder auch auf Bereitschaft prüft), wird sie blockiert und ein anderer Thread könnte ausgeführt werden, aber bei einer guten Implementierung sollte der Mutex niemals länger als ein paar Anweisungen gehalten werden, also nicht einmal eine Millisekunde. Die aktuelle Implementierung von GCC verwendet überhaupt keinen Mutex, aber der vorherige hat dies getan und das Bereitstellen des Status erfolgt durch Vertauschen von zwei Zeigern, sodass der Mutex in diesem Fall nur sehr kurz gesperrt wird.
Jonathan Wakely
@ JonathanWakely Testen mit g ++ for(int i = 0; i < 1000; i++) f.wait_for(chrono::seconds(0));dauert 43 ms Wanduhrzeit.
Daniel Kinsman
15

Für std :: future ist eine is_ready-Memberfunktion in Arbeit . In der Zwischenzeit hat die VC-Implementierung ein _Is_ready () -Mitglied.

Rick Yorgason
quelle
Beachten Sie, dass die Memberfunktion _Is_ready () NICHT threadsicher ist. Es greift unbewacht auf das Flag _Ready des zugeordneten Status zu. Dies ist zumindest bei VS2019 16.2 der Fall.
Mattias De Charleroy
10

Meine erste Wette wäre zu nennen wait_formit einem 0 Dauer, und überprüfen Sie das Ergebnis - Code, der eine der folgenden sein kann future_status::ready, future_status::deferredoder future_status::timeout.

In cppreference behaupten sie, dass valid() geprüft wird, ob das Ergebnis verfügbar ist , aber der Standard besagt, dass zurückgegeben valid()wird, truewenn *thisauf einen gemeinsam genutzten Zustand verwiesen wird , unabhängig davon, ob dieser Zustand bereit ist oder nicht.

David Rodríguez - Dribeas
quelle
7
cppreference wurde jetzt aktualisiert und gibt an, "prüft, ob die Zukunft einen gemeinsamen Zustand hat". (Ich bin mir nicht sicher, ob Sie Ihren zweiten Absatz entfernen oder bearbeiten möchten, daher werde ich ihn nicht selbst ändern.)
Standard