Nie muszę poprawnie kończyć wątku ani zmuszać go do odpowiedzi na polecenie „zakończ”. Jestem zainteresowany wymuszeniem zakończenia wątku przy użyciu czystego C ++ 11.
Nie muszę poprawnie kończyć wątku ani zmuszać go do odpowiedzi na polecenie „zakończ”. Jestem zainteresowany wymuszeniem zakończenia wątku przy użyciu czystego C ++ 11.
Odpowiedzi:
Możesz zadzwonić std::terminate()
z dowolnego wątku, a wątek, do którego się odnosisz, zakończy się siłą.
Możesz zorganizować ~thread()
wykonanie na obiekcie docelowego wątku, bez interwencji join()
ani detach()
na tym obiekcie. Będzie to miało taki sam skutek, jak opcja 1.
Można zaprojektować wyjątek, który ma destruktor, który zgłasza wyjątek. Następnie ustaw, aby wątek docelowy zgłosił ten wyjątek, gdy ma zostać zakończony na siłę. Najtrudniejszą częścią tego jest sprawienie, aby wątek docelowy zgłosił ten wyjątek.
Opcje 1 i 2 nie powodują wycieku zasobów wewnątrzprocesowych, ale przerywają każdy wątek.
Opcja 3 prawdopodobnie spowoduje wyciek zasobów, ale jest częściowo kooperacyjna, ponieważ wątek docelowy musi zgodzić się na zgłoszenie wyjątku.
Nie ma przenośnego sposobu w C ++ 11 (o którym wiem), aby nie współpracować z pojedynczym wątkiem w programie wielowątkowym (tj. Bez zabijania wszystkich wątków). Nie było motywacji do zaprojektowania takiej funkcji.
A std::thread
może mieć tę funkcję członkowską:
native_handle_type native_handle();
Możesz użyć tego do wywołania funkcji zależnej od systemu operacyjnego, aby zrobić to, co chcesz. Na przykład w systemie operacyjnym Apple ta funkcja istnieje i native_handle_type
jest rozszerzeniem pthread_t
. Jeśli odniesiesz sukces, prawdopodobnie wyciekniesz zasoby.
std::terminate
nie wywołuje statycznych destruktorów ani nie opróżnia buforów wyjściowych, więc kolejność, w jakiej zasoby są uwalniane, nie jest dobrze zdefiniowana, ani nie masz żadnej gwarancji, że jakiekolwiek dane są widoczne dla użytkownika lub zapisane w trwałym magazynie, a nawet spójne i kompletne.
exit()
lub abort()
uzyskać ten sam ogólny efekt.
Odpowiedź @Howard Hinnant jest poprawna i wyczerpująca. Ale może to zostać źle zrozumiane, jeśli zostanie odczytane zbyt szybko, ponieważ std::terminate()
(cały proces) ma taką samą nazwę jak "terminacja", o której @AlexanderVX miał na myśli (1 wątek).
Podsumowanie: "zakończ 1 wątek + na siłę (wątek docelowy nie współpracuje) + czysty C ++ 11 = Nie ma mowy."
std::terminate()
odpowiedź jest jak klasyczna złośliwa historia o Dżinnie; spełnia wszystko co do joty życzenia PO, choć prawdopodobnie nie w sposób, w jaki miał na myśli . Ten dyskretny humor sprawił, że się uśmiechnąłem. :-)
To pytanie ma w rzeczywistości głębszy charakter, a dobre zrozumienie pojęć wielowątkowości w ogóle zapewni ci wgląd w ten temat. W rzeczywistości nie ma żadnego języka ani żadnego systemu operacyjnego, który zapewniałby możliwości asynchronicznego, nagłego kończenia wątków bez ostrzeżenia, aby ich nie używać. Wszystkie te środowiska wykonawcze zdecydowanie zalecają programistom, a nawet wymagają tworzenia aplikacji wielowątkowych w oparciu o kooperatywne lub synchroniczne kończenie wątków. Powodem tych powszechnych decyzji i porad jest to, że wszystkie są zbudowane na podstawie tego samego ogólnego modelu wielowątkowości.
Porównajmy koncepcje wieloprocesorowe i wielowątkowe, aby lepiej zrozumieć zalety i ograniczenia drugiej.
Wieloprocesorowość zakłada podzielenie całego środowiska wykonawczego na zbiór całkowicie izolowanych procesów kontrolowanych przez system operacyjny. Proces obejmuje i izoluje stan środowiska wykonawczego, w tym lokalną pamięć procesu i znajdujące się w nim dane oraz wszystkie zasoby systemowe, takie jak pliki, gniazda, obiekty synchronizacji. Izolacja jest krytycznie ważną cechą procesu, ponieważ ogranicza propagację błędów przez granice procesu. Innymi słowy, żaden proces nie może wpłynąć na spójność innego procesu w systemie. To samo dotyczy zachowania procesu, ale w mniej ograniczony i bardziej rozmyty sposób. W takim środowisku każdy proces może zostać zabity w dowolnym "dowolnym" momencie, ponieważ po pierwsze każdy proces jest izolowany, po drugie,
Z kolei wielowątkowość zakłada uruchamianie wielu wątków w tym samym procesie. Ale wszystkie te wątki znajdują się w tym samym polu izolacji i nie ma żadnej kontroli systemu operacyjnego nad wewnętrznym stanem procesu. W rezultacie każdy wątek może zmienić globalny stan procesu, a także go uszkodzić. Jednocześnie punkty, w których stan wątku jest dobrze znany jako bezpieczny do całkowitego zabicia wątku, zależy od logiki aplikacji i nie są znane ani dla systemu operacyjnego, ani dla środowiska uruchomieniowego języka programowania. W rezultacie zakończenie wątku w dowolnym momencie oznacza zabicie go w dowolnym punkcie ścieżki wykonania i może łatwo doprowadzić do uszkodzenia danych w całym procesie, wycieku pamięci i uchwytów,
Z tego powodu powszechnym podejściem jest wymuszenie na programistach zaimplementowania synchronicznego lub kooperacyjnego zakończenia wątku, w którym jeden wątek może zażądać zakończenia innego wątku, a inny wątek w dobrze zdefiniowanym punkcie może sprawdzić to żądanie i rozpocząć procedurę zamykania z dobrze zdefiniowanego stanu z uwolnieniem wszystkich globalnych zasobów systemowych i lokalnych zasobów obejmujących cały proces w bezpieczny i spójny sposób.
Wskazówki dotyczące używania funkcji zależnej od systemu operacyjnego do kończenia wątku C ++:
std::thread::native_handle()
tylko może uzyskać prawidłowy natywny typ uchwytu wątku przed wywołaniem join()
lub detach()
. Po tym native_handle()
zwraca 0 - pthread_cancel()
będzie coredump.
Aby skutecznie wywołać funkcję kończenia wątku natywnego (np. pthread_cancel()
), Musisz zapisać natywny uchwyt przed wywołaniem std::thread::join()
lub std::thread::detach()
. Aby Twój natywny terminator zawsze miał prawidłowy natywny uchwyt do użycia.
Więcej wyjaśnień można znaleźć na stronie : http://bo-yang.github.io/2017/11/19/cpp-kill-detached-thread .
Wydaje mi się, że wątek, który należy zabić, jest albo w jakimkolwiek trybie oczekiwania, albo wykonuje ciężką pracę. Sugerowałbym użycie „naiwnego” sposobu.
Zdefiniuj globalne wartości logiczne:
std::atomic_bool stop_thread_1 = false;
Umieść poniższy kod (lub podobny) w kilku kluczowych punktach w taki sposób, aby wszystkie funkcje na stosie wywołań zwracały się do momentu, gdy wątek naturalnie się zakończy:
if (stop_thread_1)
return;
Następnie, aby zatrzymać wątek z innego (głównego) wątku:
stop_thread_1 = true;
thread1.join ();
stop_thread_1 = false; //(for next time. this can be when starting the thread instead)