Czasami muszę użyć, std::thread
aby przyspieszyć moją aplikację. Wiem też, że join()
czeka, aż wątek się zakończy. Łatwo to zrozumieć, ale jaka jest różnica między dzwonieniem detach()
a nie dzwonieniem?
Pomyślałem, że bez detach()
wątku metoda wątku będzie działać niezależnie od wątku.
Nie odłączanie:
void Someclass::Somefunction() {
//...
std::thread t([ ] {
printf("thread called without detach");
});
//some code here
}
Dzwonienie z odłączaniem:
void Someclass::Somefunction() {
//...
std::thread t([ ] {
printf("thread called with detach");
});
t.detach();
//some code here
}
std
iboost
wątki majądetach
i sąjoin
wzorowane na wątkach POSIX.Odpowiedzi:
W destruktorze
std::thread
,std::terminate
jest wywoływane, jeśli:t.join()
)t.detach()
)W związku z tym zawsze należy utworzyć wątek
join
lubdetach
wątek, zanim przepływy wykonania dotrą do destruktora.Gdy program się kończy (tj.
main
Zwraca), pozostałe odłączone wątki wykonywane w tle nie są oczekiwane; zamiast tego ich wykonanie zostaje zawieszone, a ich obiekty lokalne dla wątków zniszczone.Co najważniejsze, oznacza to, że stos tych wątków nie jest rozwijany, a zatem niektóre destruktory nie są wykonywane. W zależności od działań, jakie te destruktory miały podjąć, może to być tak zła sytuacja, jak gdyby program się zawiesił lub został zabity. Miejmy nadzieję, że system operacyjny zwolni blokady plików itp., Ale mogłeś uszkodzić pamięć współdzieloną, częściowo zapisane pliki i tym podobne.
Więc powinieneś użyć
join
lubdetach
?join
detach
źródło
Powinieneś zadzwonić,
detach
jeśli nie zamierzasz czekać na zakończenie wątku,join
ale zamiast tego wątek będzie po prostu działał, aż zostanie zakończony, a następnie zakończy działanie bez czekania na główny wątek.detach
zasadniczo uwolni zasoby potrzebne do wdrożeniajoin
.Jest to błąd krytyczny, jeśli obiekt nitki kończy swoje życie i ani
join
niedetach
został wywołany; w tym przypadkuterminate
jest wywoływana.źródło
Po odłączeniu wątku oznacza to, że nie musisz tego robić
join()
przed wyjściemmain()
.Biblioteka wątków będzie faktycznie czekać na każdy taki wątek poniżej głównego , ale nie powinieneś się tym przejmować.
detach()
przydaje się głównie wtedy, gdy masz zadanie do wykonania w tle, ale nie przejmujesz się jego wykonaniem. Tak jest zwykle w przypadku niektórych bibliotek. Mogą po cichu utworzyć wątek roboczy w tle i odłączyć go, abyś nawet tego nie zauważył.źródło
Ta odpowiedź ma na celu udzielenie odpowiedzi na pytanie w tytule, a nie wyjaśnienie różnicy między
join
idetach
. Więc kiedy powinienstd::thread::detach
należy użyć?W prawidłowo utrzymywanym C ++ kod w
std::thread::detach
ogóle nie powinien być używany. Programista musi upewnić się, że wszystkie utworzone wątki z wdziękiem kończą pracę, zwalniając wszystkie nabyte zasoby i wykonując inne niezbędne działania czyszczące. Oznacza to, że rezygnacja z własności wątków przez wywołaniedetach
nie jest opcją, a zatemjoin
powinna być używana we wszystkich scenariuszach.Jednak niektóre aplikacje opierają się na starych i często niezbyt dobrze zaprojektowanych i obsługiwanych interfejsach API, które mogą zawierać funkcje blokujące na czas nieokreślony. Przenoszenie wywołań tych funkcji do dedykowanego wątku w celu uniknięcia blokowania innych rzeczy jest powszechną praktyką. Nie ma sposobu, aby taki wątek wyszedł z wdziękiem, więc użycie
join
spowoduje po prostu zablokowanie głównego wątku. To sytuacja, w której użyciedetach
byłoby mniej złą alternatywą dla, powiedzmy, przydzielaniathread
obiektu z dynamicznym czasem przechowywania, a następnie celowego wycieku.źródło
Według cppreference.com :
Na przykład:
Zwróć uwagę na zmienną lokalną:,
my_thread
gdy czas życiamy_thread
się skończył, destruktorstd::thread
zostanie wywołany istd::terminate()
zostanie wywołany w ramach destruktora.Ale jeśli używasz
detach()
, nie powinieneśmy_thread
już używać , nawet jeśli żywotnośćmy_thread
się skończy, nic się nie stanie z nowym wątkiem.źródło
&
w przechwytywaniu lambda, używasz zmiennych otaczającego zakresu przez odwołanie - więc lepiej upewnij się, że czas życia każdego odwołania jest dłuższy niż czas życia wątku.