Jak mogę sprawdzić, czy std::thread
nadal działa (w sposób niezależny od platformy)? Brakuje mu timed_join()
metody i joinable()
nie jest do tego przeznaczona.
Myślałem o zablokowaniu muteksu za pomocą a std::lock_guard
w wątku i użyciu try_lock()
metody muteksu w celu określenia, czy nadal jest zablokowany (wątek działa), ale wydaje mi się to niepotrzebnie skomplikowane.
Czy znasz bardziej elegancką metodę?
Aktualizacja: Żeby było jasne: chcę sprawdzić, czy wątek został czysty, czy nie. W tym celu uważa się, że „wiszący” nić działa.
c++
multithreading
c++11
stdthread
kispaljr
źródło
źródło
wait()
, a jeśli tak, jeśli jeszcze tego nie zrobiłeśwait()
, z definicji musi działać. Ale to rozumowanie może być niedokładne.Odpowiedzi:
Jeśli chcesz korzystać z C ++ 11
std::async
istd::future
wykonywać swoje zadania, możesz skorzystać zwait_for
funkcji,std::future
aby sprawdzić, czy wątek nadal działa w zgrabny sposób:#include <future> #include <thread> #include <chrono> #include <iostream> int main() { using namespace std::chrono_literals; /* Run some task on new thread. The launch policy std::launch::async makes sure that the task is run asynchronously on a new thread. */ auto future = std::async(std::launch::async, [] { std::this_thread::sleep_for(3s); return 8; }); // Use wait_for() with zero milliseconds to check thread status. auto status = future.wait_for(0ms); // Print status. if (status == std::future_status::ready) { std::cout << "Thread finished" << std::endl; } else { std::cout << "Thread still running" << std::endl; } auto result = future.get(); // Get result. }
Jeśli musisz użyć
std::thread
, możesz użyć,std::promise
aby uzyskać przyszły obiekt:#include <future> #include <thread> #include <chrono> #include <iostream> int main() { using namespace std::chrono_literals; // Create a promise and get its future. std::promise<bool> p; auto future = p.get_future(); // Run some task on a new thread. std::thread t([&p] { std::this_thread::sleep_for(3s); p.set_value(true); // Is done atomically. }); // Get thread status using wait_for as before. auto status = future.wait_for(0ms); // Print status. if (status == std::future_status::ready) { std::cout << "Thread finished" << std::endl; } else { std::cout << "Thread still running" << std::endl; } t.join(); // Join thread. }
Oba te przykłady dadzą:
Dzieje się tak, ponieważ stan wątku jest sprawdzany przed zakończeniem zadania.
Ale z drugiej strony może być łatwiej po prostu zrobić to tak, jak inni już wspominali:
#include <thread> #include <atomic> #include <chrono> #include <iostream> int main() { using namespace std::chrono_literals; std::atomic<bool> done(false); // Use an atomic flag. /* Run some task on a new thread. Make sure to set the done flag to true when finished. */ std::thread t([&done] { std::this_thread::sleep_for(3s); done = true; }); // Print status. if (done) { std::cout << "Thread finished" << std::endl; } else { std::cout << "Thread still running" << std::endl; } t.join(); // Join thread. }
Edytować:
Istnieje również
std::packaged_task
do użycia zstd::thread
czystszym rozwiązaniem niż użyciestd::promise
:#include <future> #include <thread> #include <chrono> #include <iostream> int main() { using namespace std::chrono_literals; // Create a packaged_task using some task and get its future. std::packaged_task<void()> task([] { std::this_thread::sleep_for(3s); }); auto future = task.get_future(); // Run task on new thread. std::thread t(std::move(task)); // Get thread status using wait_for as before. auto status = future.wait_for(0ms); // Print status. if (status == std::future_status::ready) { // ... } t.join(); // Join thread. }
źródło
std::atomic<bool> done(false);
? Czybool
atomowy nie jest domyślnie?std::atomic
.sizeof(bool)
jest zdefiniowana w implementacji i może być> 1, więc możliwe jest, że nastąpi częściowy zapis. Jest też kwestia spójności pamięci podręcznej ...Łatwym rozwiązaniem jest posiadanie zmiennej boolowskiej, którą wątek ustawia na true w regularnych odstępach czasu, a która jest sprawdzana i ustawiana na false przez wątek, który chce znać status. Jeśli zmienna jest zbyt długa, to wątek nie jest już uważany za aktywny.
Bardziej bezpiecznym sposobem na wątki jest posiadanie licznika, który jest zwiększany przez wątek podrzędny, a wątek główny porównuje licznik z przechowywaną wartością, a jeśli to samo po zbyt długim czasie, wątek podrzędny jest uważany za nieaktywny.
Zauważ jednak, że w C ++ 11 nie ma sposobu, aby faktycznie zabić lub usunąć wątek, który się zawiesił.
Edytuj Jak sprawdzić, czy wątek został czysty, czy nie: Zasadniczo ta sama technika, co opisana w pierwszym akapicie; Miej zmienną logiczną zainicjowaną jako false. Ostatnią rzeczą, jaką robi wątek potomny, jest ustawienie wartości true. Wątek główny może następnie sprawdzić tę zmienną, a jeśli to prawda, wykonać złączenie w wątku potomnym bez większego (jeśli w ogóle) blokowania.
Edit2 Jeśli wątek kończy pracę z powodu wyjątku, mają dwie "główne" funkcje wątku: Pierwsza z nich ma
try
-catch
wewnątrz której wywołuje drugą "prawdziwą" funkcję głównego wątku. Ta pierwsza główna funkcja ustawia zmienną „have_exited”. Coś takiego:bool thread_done = false; void *thread_function(void *arg) { void *res = nullptr; try { res = real_thread_function(arg); } catch (...) { } thread_done = true; return res; }
źródło
thread_done
, ten kod jest zepsuty bez bariery pamięci. Użyjstd::atomic<bool>
zamiast tego.bool
, w którym główny wątek odczytuje z niego - to wymaga bariery pamięci.std::atomic<bool>
jest tu konieczne.Ten prosty mechanizm służy do wykrywania wykończenia gwintu bez blokowania metody łączenia.
std::thread thread([&thread]() { sleep(3); thread.detach(); }); while(thread.joinable()) sleep(1);
źródło
join()
z jakiegoś wątku, który nie czeka, aż wątek straci swojąjoinable()
właściwość, w przeciwnym razie będzie pętli bez końca (tj.joinable()
zwróci true, dopóki wątek nie będziejoin()
ed i nie do końca)thread.detach()
część, powyższy program nigdy się nie zakończy.Utwórz muteks, do którego ma dostęp zarówno działający wątek, jak i wątek wywołujący. Kiedy uruchomiony wątek rozpoczyna się, blokuje muteks, a kiedy się kończy, odblokowuje muteks. Aby sprawdzić, czy wątek nadal działa, wątek wywołujący wywołuje mutex.try_lock (). Zwracaną wartością jest stan wątku. (Po prostu upewnij się, że odblokowałeś muteks, jeśli try_lock zadziałał)
Jeden mały problem z tym, mutex.try_lock () zwróci false między momentem utworzenia wątku a zablokowaniem muteksu, ale można tego uniknąć stosując nieco bardziej złożoną metodę.
źródło
std::mutex
do tego rodzaju sygnalizacji (głównie z powodu zwykle implementacji muteksu). Anatomic_flag
działa równie dobrze w tym przypadku, przy znacznie mniejszym obciążeniu. Astd::future
może być nawet lepszy, ponieważ wyraźniej wyraża zamiar. Należy również pamiętać, żetry_lock
może się nie udać fałszywie, więc powrót jest nie koniecznie status wątku (choć prawdopodobnie nie zaszkodzi Ci dużo w tym konkretnym przypadku).Zawsze możesz sprawdzić, czy id wątku różni się od domyślnej konstrukcji std :: thread :: id (). Działający wątek ma zawsze autentyczny powiązany identyfikator. Staraj się unikać zbyt wielu wymyślnych rzeczy :)
źródło
Z pewnością należy zainicjować zmienną opakowaną w muteks
false
, na którą wątek ustawia siętrue
jako ostatnia rzecz, jaką robi przed wyjściem. Czy to jest wystarczająco atomowe dla Twoich potrzeb?źródło
std::atomic<bool>
dba o to za Ciebie, dlatego jest to prawdziwa odpowiedź IMO.