2013-03-27 11 views
6

Próbuję poprawnie zakończyć moją wielowątkową aplikację C++ 11 po otrzymaniu sygnału SIGINT (^C), ale z jakiegoś powodu nie propaguje ona do wątków potomnych , chociaż główny wątek reaguje na to dobrze.Propagowanie sygnału (SIGINT) do C++ 11 wątków

Dla instnce (jak w przykładzie kodu poniżej), jeśli mamy jakąś funkcję blokowania wewnątrz wątku (jak sleep()), to zajmie się całą ^C kontrolę od Ciebie, jeśli zainstalowano żadnych haczyków SIGNT użyciu, powiedzmy, sigaction() funkcji .

Czy istnieje sposób naprawienia lub obejścia takiego zachowania? Czy istnieje sposób propagowania odbieranych sygnałów do wątków potomnych?

EDIT: zastąpiony POSIX sleep() z C++ 11 std::this_thread::sleep_for()

#include <iostream> 
#include <thread> 
#include <chrono> 
#include <signal.h> // for sigaction() function 

static int signaled = 0; 

void threaded_foo() { 
    while (!signaled) { 
    // pressing ^C now will not lead to correct termination, because we are 
    // sleeping for a long time (100500 seconds) and do not respond to 
    // SIGINT for some tricky reason i am looking a bypassage for. 
    std::chrono::seconds duration(100500); 
    std::this_thread::sleep_for(duration); 
    } 
    std::cout << "Correct termination\n"; 
} 

void sighandler(int sig, siginfo_t *siginfo, void *context) { 
    signaled = 1; 
} 

void install_sig_hooks() { 
    struct sigaction action; 
    memset(&action, 0, sizeof(struct sigaction)); 
    action.sa_sigaction = sighandler; 
    action.sa_flags  = SA_SIGINFO; 
    sigaction(SIGINT, &action, NULL); 
} 

int main(int argc, char **argv) { 
    install_sig_hooks(); 

    std::thread t(threaded_foo); 
    t.join(); 
    return 0; 
} 

EDIT2 więc rozwiązaniem było zastąpienie wszystkich blokowania połączeń z non-blocking odpowiedniki takich mechanizmów jak i zmiennych stanie i odpytywania .

Rzeczywiste pytanie pozostaje bez odpowiedzi, ponieważ aktualne oprogramowanie (i ewentualnie sprzęt) nie jest zaprojektowane w taki sposób, aby obsługiwać sygnały więcej niż w jednym wątku, który powinien informować innych, co mają robić po otrzymaniu sygnałów.

+0

Czemu mieszanie funkcji POSIX 'sleep' z wątkami C++ 11? –

+0

Tylko dla przykładu, w prawdziwej aplikacji jest to funkcja ZeroMQ send() z dokładnie takim samym efektem. –

+0

cóż, w rzeczy samej, jest to zły przykład, powinienem zamiast tego użyć 'std :: this_thread :: sleep_for()'. Przepraszam, pozwól mi poprawić mój przykład. –

Odpowiedz

4

Próbuję poprawnie zakończyć moją wielowątkową aplikację C++ 11 po otrzymaniu sygnału SIGINT (^ C to jest), ale z jakiegoś powodu nie propaguje się do wątków potomnych, chociaż główny wątek odpowiada na to dobrze.

POSIX distinguishes signals targeted to process or a thread. W obu przypadkach tylko jeden wątek odbiera sygnał:

W czasie generowania należy określić, czy sygnał został wygenerowany dla procesu, czy dla określonego wątku w procesie. Sygnały generowane przez niektóre działania przypisane do określonego wątku, takie jak błąd sprzętowy, są generowane dla wątku, który spowodował wygenerowanie sygnału. Sygnały wygenerowane w powiązaniu z identyfikatorem procesu lub identyfikatorem grupy procesów lub zdarzeniem asynchronicznym, takim jak działanie terminalu, są generowane dla tego procesu.

...

... Sygnały generowane w procesie doręcza się dokładnie jeden z tych wątków w obrębie procesu, który jest w wywołaniu funkcji polecenia sigwait() lub wybranie tego sygnału nie zablokował dostarczenia sygnału. Jeśli w wywołaniu funkcji sigwait() nie ma wątków w wywołaniu tego sygnału, a wszystkie wątki w ramach dostarczania sygnału bloku procesu, sygnał powinien pozostać w toku procesu, aż wątek wywoła funkcję sigwait() wybierając sygnał, wątek odblokowuje dostarczanie sygnału lub działanie związane z sygnałem jest ustawione tak, aby ignorować sygnał.

W procesie wielowątkowym powszechnym rozwiązaniem jest blokowanie sygnałów procesowych, które mają być obsługiwane we wszystkich wątkach oprócz jednego. Ten jeden wątek normalnie poradziłby sobie z wszystkimi sygnałami procesowymi i powiedziałby innym wątkom, co zrobić (na przykład zakończyć).

Ponadto, ponieważ signaled jest ustawiony przez procedurę obsługi sygnału, powinno zostać uznane volatile, jest to jeden z dwóch przypadków użycia volatile została wprowadzona do:

static int volatile signaled = 0; 
+0

Twoja odpowiedź rodzi dwa nowe pytania: 1) w jaki sposób przerywasz wątek w C++ 11, więc czy wszystkie uśpienia() s obudzą się? i 2) jak faktycznie zakończyć wątek za pomocą inwentarza C++ 11? –

+0

Dzięki za niestabilne zawiadomienie, ale tylko dla zapisu ten sam kod działa dobrze z rozsądnymi wartościami czasu trwania snu, jak jedna sekunda. Chociaż to zachowanie może nie być tak dobrze zdefiniowane. –

+1

@AlexanderTumin Polecam przeciw zakłóceniom wątków, ponieważ biblioteki innych firm, których możesz używać, mogą nie obsługiwać przerw w prawidłowy sposób. Powiedz grzecznie grzecznie, aby przerwały, a następnie poczekaj. Zakłada to, że wszystkie twoje wątki mają jakąś pętlę zdarzeń, aby można było im kazać zakończyć. –