Il modello di funzione std::async
(parte del modello <future>
) viene utilizzato per avviare un'attività (eventualmente) asincrona. Restituisce un oggetto std::future
, che alla fine manterrà il valore di ritorno della funzione parametro std::async
.
Quando il valore è necessario, si chiama get() nell'istanza std::future
; questo blocca il thread fino a quando il futuro è pronto e quindi restituisce il valore. std::launch::async
o std::launch::deferred
possono essere specificati come primo parametro su std::async
per specificare come viene eseguita l'attività.
std::launch::async
indica che la chiamata di funzione deve essere eseguita sul proprio (nuovo) thread. (Prendere in considerazione il commento dell'utente @ T.C.).
std::launch::deferred
indica che la chiamata di funzione deve essere posticipata fino a quando non viene chiamato su wait()
o get()
. La proprietà del futuro può essere trasferita su un'altra discussione prima che ciò accada.
std::launch::async | std::launch::deferred
indica che l'implementazione può scegliere. Questa è l'opzione predefinita (quando non ne specifichi uno tu stesso). Può decidere di eseguire in modo sincrono.
È una nuova discussione sempre avviata in questo caso?
Da 1., possiamo dire che viene sempre lanciato un nuovo thread.
Le mie ipotesi [su std :: launch :: deferred] sono corrette?
Da 2., possiamo dire che le vostre ipotesi sono corrette.
Che cosa dovrebbe significare? [In relazione a un nuovo thread in fase di lancio o meno a seconda della realizzazione]
Da 3., come std::launch::async | std::launch::deferred
è l'opzione di default, significa che l'implementazione della funzione template std::async
deciderà se si creerà una nuova discussione o no. Ciò è dovuto al fatto che alcune implementazioni potrebbero verificare la sovrascrittura.
ATTENZIONE
La sezione seguente non è correlato alla tua domanda, ma penso che sia importante tenere a mente.
Lo standard C++ dice che se un std::future
tiene l'ultimo riferimento allo stato condiviso corrispondente a una chiamata a una funzione asincrona, distruttore che std :: del futuro deve bloccare finché il filo per le finiture funzione asincrono in esecuzione. Un'istanza di std::future
restituita da std::async
bloccherà quindi il suo distruttore.
void operation()
{
auto func = [] { std::this_thread::sleep_for(std::chrono::seconds(2)); };
std::async(std::launch::async, func);
std::async(std::launch::async, func);
std::future<void> f{ std::async(std::launch::async, func) };
}
Questo codice fuorviante può farvi pensare che i std::async
chiamate sono asincrone, in realtà sono sincroni. Le istanzerestituite da std::async
sono temporanee e verranno bloccate perché il loro distruttore viene chiamato a destra quando std::async
restituisce come non sono assegnati a una variabile.
La prima chiamata a std::async
verrà bloccata per 2 secondi, seguita da altri 2 secondi di blocco dalla seconda chiamata a std::async
. Potremmo pensare che l'ultima chiamata a std::async
non blocchi, poiché memorizziamo la sua istanza restituita std::future
in una variabile, ma poiché si tratta di una variabile locale che viene distrutta alla fine dell'ambito, verrà effettivamente bloccata per altri 2 secondi alla fine dell'ambito della funzione, quando la variabile locale f viene distrutta.
In altre parole, la chiamata alla funzione operation()
bloccherà qualsiasi thread in cui viene chiamato in sincrono per circa 6 secondi. Tali requisiti potrebbero non esistere in una versione futura dello standard C++.
Le fonti di informazione sono utilizzati per compilare queste note:
C++ concorrenza in Azione: Practical multithreading, Anthony Williams
Scott Meyers' post del blog: http://scottmeyers.blogspot.ca/2013/03/stdfutures-from-stdasync-arent-special.html
"come se" significa che può teoricamente riutilizzare un thread esistente (ad esempio, in un pool di thread) fino a quando il il comportamento è indistinguibile. In pratica, pochissime (se ce ne sono) implementazioni lo fanno perché "come se un nuovo thread" richiedesse di distruggere e ricreare tutte le variabili locali del thread. –
@ T.C. o implementare (pesanti) variabili locali di coroutine. Ciascun thread riceve una coroutine predefinita e 'thread_local' è coroutine locale. Il 'async' può creare una coroutine, che la coroutine può essere ritagliata in un altro thread ed eseguire. Vale a dire, emulare il threading (con le coroutine) sopra un modello di thread fornito dal sistema operativo? – Yakk
Ho sentito che 'std :: async' è rotto, è vero? –