2013-03-27 3 views
6

Sto cercando di terminare correttamente la mia applicazione C++ 11 multi-threaded alla ricezione del segnale SIGINT (^C è), ma per qualche motivo non si propaga ai thread figlio , anche se il thread principale risponde bene.Segnale di propagazione (SIGINT) a C++ 11 thread

Per instnce (come nell'esempio di codice di seguito), se abbiamo una qualche funzione di blocco all'interno di filo (come sleep()), ci vorranno tutte ^C controllo da te se installato alcun hook signt utilizzando, per esempio, sigaction() funzione .

C'è un modo per risolvere o aggirare questo comportamento? C'è un modo per propagare i segnali ricevuti principali ai thread figli?

EDIT: sostituito POSIX sleep() con 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 Quindi la soluzione era di sostituire tutte le chiamate di blocco con controparti non-blocking e meccanismi come variabili di condizione e polling .

La domanda rimane senza risposta reale come software corrente (e, possibilmente, hardware) non è progettato in modo di gestire segnali più quindi in un thread, che si suppone uno a dire agli altri cosa fare dopo aver ricevuto segnali.

+0

Perché sei mescolando i POSIX 'sleep' funzione con i thread C++ 11? –

+0

Solo a titolo di esempio, nella vera applicazione è la funzione Send() di ZeroMQ con esattamente lo stesso effetto. –

+0

beh, in effetti, è un cattivo esempio, avrei dovuto usare 'std :: this_thread :: sleep_for()' invece. Mi dispiace, lascia che corregga il mio esempio. –

risposta

4

Sto cercando di terminare correttamente la mia applicazione C++ 11 multi-threaded alla ricezione del segnale SIGINT (^ C lo è), ma per qualche motivo non si propaga ai thread figli, sebbene il thread principale risponda ad esso bene.

POSIX distinguishes signals targeted to process or a thread. In entrambi i casi, solo un thread riceve il segnale:

Al momento della generazione, è necessario determinare se il segnale è stato generato per il processo o per una filettatura specifica all'interno del processo. I segnali generati da un'azione attribuibile a un determinato thread, ad esempio un errore hardware, devono essere generati per il thread che ha causato la generazione del segnale. I segnali generati in associazione con un ID di processo o un ID del gruppo di processi o un evento asincrono, come l'attività del terminale, devono essere generati per il processo.

...

... segnali generati per il processo sono consegnati esattamente uno di quei fili all'interno del processo che è in una chiamata a una funzione sigwait() selezionare il segnale o non ha bloccato la consegna del segnale. Se non ci sono thread in una chiamata a una funzione sigwait() che seleziona quel segnale, e se tutti i thread all'interno del processo bloccano l'invio del segnale, il segnale rimarrà in sospeso sul processo fino a quando un thread chiama una funzione sigwait() che lo seleziona segnale, un thread sblocca la consegna del segnale o l'azione associata al segnale viene impostata per ignorare il segnale.

In un processo multi-thread una soluzione comune è bloccare i segnali di processo che si intende gestire in tutti i thread tranne uno. Quello thread normalmente gestirà tutti i segnali di processo e dirà agli altri thread cosa fare (ad es. Terminare).

Inoltre, poiché signaled è impostata dal gestore di segnale, dovrebbe essere dichiarato volatile, questo è uno dei due casi d'uso volatile è stato introdotto per:

static int volatile signaled = 0; 
+0

La tua risposta pone due nuove domande: 1) come interrompi il thread in C++ 11, quindi tutti gli sleep() dovrebbero svegliarsi? e 2) come si fa a terminare il thread con l'inventario C++ 11? –

+0

Grazie per l'avviso volatile, ma solo per la cronologia lo stesso codice funziona bene con sani valori di durata del sonno, come un secondo. Anche se questo comportamento potrebbe non essere così ben definito. –

+1

@AlexanderTumin Raccomanderei contro le interruzioni di thread, perché le librerie di terze parti che potresti utilizzare potrebbero non gestire correttamente le interruzioni. Dillo cortesemente ai tuoi argomenti per terminare e poi aspetta. Ciò presuppone che tutti i tuoi thread abbiano una sorta di ciclo di eventi, in modo che possa essere detto di terminare. –