Szablon funkcji std::async
(część szablonu <future>
) służy do uruchamiania (prawdopodobnie) zadania asynchronicznego. Zwraca obiekt std::future
, który ostatecznie zatrzyma wartość zwracaną przez funkcję parametru std::async
.
Gdy wartość jest potrzebna, wywołujemy metodę get() na instancji std::future
; blokuje to wątek, aż przyszłość będzie gotowa, a następnie zwróci wartość. std::launch::async
lub std::launch::deferred
można określić jako pierwszy parametr dla std::async
w celu określenia sposobu uruchomienia zadania.
std::launch::async
wskazuje, że wywołanie funkcji musi być uruchomione na osobnym (nowym) wątku. (Weź pod uwagę komentarz użytkownika @ T.C.).
std::launch::deferred
oznacza, że wywołanie funkcji ma zostać odroczone do czasu wywołania wait()
lub get()
w przyszłości. Własność przyszłości może zostać przeniesiona do innego wątku, zanim to nastąpi.
std::launch::async | std::launch::deferred
wskazuje, że wdrożenie może wybrać. Jest to domyślna opcja (jeśli nie określisz osobiście). Może zdecydować się na uruchomienie synchroniczne.
Czy w tym przypadku zawsze pojawiał się nowy wątek?
Od 1., możemy powiedzieć, że nowy wątek jest zawsze uruchamiany.
Czy moje założenia [na std :: launch :: odłożone] są prawidłowe?
Od 2. Możemy powiedzieć, że twoje założenia są poprawne.
Co to ma znaczyć? [W odniesieniu do nowego wątku jest uruchomiona lub nie w zależności od implementacji]
Od 3., jak std::launch::async | std::launch::deferred
to opcja domyślna, oznacza to, że realizacja funkcji szablonu std::async
zadecyduje, czy będzie tworzyć nowy wątek lub nie. Dzieje się tak dlatego, że niektóre implementacje mogą być sprawdzane przez nadmierne planowanie.
UWAGA
Poniższa sekcja nie jest związane z pytaniem, ale myślę, że ważne jest, aby pamiętać.
Standard C++ mówi, że jeśli std::future
zawiera ostatnie odniesienie do stanu współdzielonego odpowiadającego wywołaniu funkcji asynchronicznej, to destruktor std :: future musi blokować, dopóki wątek dla asynchronicznie uruchomionej funkcji nie zostanie zakończony. Instancja std::future
zwrócona przez std::async
będzie zatem blokować w swoim destruktorze.
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) };
}
To mylące kod może sprawić, że rozmowy std::async
są asynchroniczne, w rzeczywistości są synchroniczne. Instancje std::future
zwrócone przez std::async
są tymczasowe i będą blokować, ponieważ ich destruktor jest wywoływany prawidłowo, gdy zwraca się do nich, ponieważ nie są one przypisane do zmiennej.
Pierwsze połączenie z std::async
zablokuje się na 2 sekundy, a następnie kolejne 2 sekundy zablokowania od drugiego połączenia do std::async
. Możemy myśleć, że ostatnie wywołanie do std::async
nie blokuje, ponieważ przechowujemy zwróconą instancję std::future
w zmiennej, ale ponieważ jest to zmienna lokalna, która jest zniszczona na końcu zakresu, to faktycznie zablokuje się na dodatkowe 2 sekundy na końcu zakresu funkcji, gdy zmienna lokalna f jest zniszczona.
Innymi słowy, wywoływanie funkcji operation()
zablokuje synchronizowany wątek przez około 6 sekund. Takie wymagania mogą nie istnieć w przyszłej wersji standardu C++.
Źródła informacji Kiedyś skompilować te Uwagi:
C++ współbieżność w działaniu: Praktyczne wielowątkowość, Anthony Williams
Scott Meyers' blogu: http://scottmeyers.blogspot.ca/2013/03/stdfutures-from-stdasync-arent-special.html
„jakby” oznacza, że może teoretycznie ponowne wykorzystanie istniejącego wątku (np w puli wątków) tak długo, jak zachowanie jest nie do odróżnienia. W praktyce, bardzo niewiele implementacji (jeśli takowa) robi to, ponieważ "tak, jakby nowy wątek" wymaga zniszczenia i odtworzenia wszystkich zmiennych lokalnych wątku. –
@ T.C. lub implementuj (ciężkie) zmienne lokalne typu coroutine. Niech każdy wątek otrzyma domyślny coroutine, a 'thread_local' jest coroutine local. 'Asynchroniczny' może utworzyć współprogram, że coroutine może zostać przeniesiony do innego wątku i uruchomiony. Tj., Emulować wątków (z coroutines) na górze dostarczonego przez system wątku? – Yakk
Uważam, że 'std :: async' jest zepsuty, czy to prawda? –