2016-07-11 32 views
1

Wenn ich ein Programm wie diese (in Pseudo-Code):Gibt es eine Möglichkeit, Atomarität sicherzustellen, während ein Multithread-Programm mit Signalhandlern zur Verfügung steht?

mutex_lock; 
func() { 
    lock(mutex_lock); 
    // Some code (long enough to make a 
    // race condition if no proper synchronisation 
    // is available). We also going to call a signal, 
    // say, SIGINT, through (ctrl-c), while we are in 
    // the range of locking and unlocking the lock. 
    unlock(mutex_lock); 
} 

sig_handler_func(sig) { 
    // Say, we are handling SIGINT (ctrl-c) signal 
    // And we need to call func from here too. 
    if (sig == SIGINT) { 
     func(); 
    } 
} 

main() { 
    // Calling func from main 
    func(); 
} 

dann gäbe es ein Deadlock bei dem Versuch, das Schloss in func zu erwerben, während es bereits aus dem ‚Haupt‘ Anrufer erworben wird. Ich habe mich gefragt, ob es eine Möglichkeit gibt, die Signalbehandlung in der C-Sprache zu unterbrechen, insbesondere wenn in diesem Beispiel func eingegeben und die Sperre akquiriert wird, und die Signalbehandlung wiederaufgenommen wird und die Handler beim Verlassen der Funktion aufgerufen werden.

+0

Die Interaktion zwischen Threads und Signalverarbeitung in C selbst ist nicht definiert. Sie müssen genauer sein. Ist Ihr System ein POSIX-System? Bitte kennzeichnen Sie Ihre Frage entsprechend. –

Antwort

2

Sie wollen pthread_sigmask, die Multi-Thread-Version von sigprocmask

Hier einige Beispiel-Pseudocode:

int 
main(void) 
{ 
    sigset_t omask; 
    sigset_t nmask; 

    // add as many signals as you want to the mask ... 
    sigemptyset(&nmask); 
    sigaddset(&nmask,SIGINT); 

    // [temporarily] block signals 
    pthread_sigmask(SIG_BLOCK,&nmask,&omask); 

    // call function safely 
    func(); 

    // restore signal mask 
    pthread_sigmask(SIG_SETMASK,&omask,NULL); 

    // pending signals should occur now ... 
} 

ich nicht ganz sicher bin, aber können Sie pthread_sigmask verwenden müssen Signale in alle zu blockieren aber ein Thread und tun Sie das obige nur aus diesem Thread.

Auch ich würde nachlässig sein, wenn ich nicht sage, dass ich Ihren Code umgestalten würde. Die Anzahl der Dinge, die Sie in einem Signal-Handler tun können [von dieser Seite] begrenzt ist (zB keine malloc, keine printf, etc.)

Widmen einen Thread für Signalverarbeitung und nachdem er sigsetjmp tun und die Signal-Handler tun siglongjmp .

Oder der Signal-Handler hat einen flüchtigen globalen Wert gesetzt (z. B. signal_occurred), der auf Basisebene überwacht wird.

Somit können alle "schweren Arbeiten", die Sie im Signal-Handler durchführen, von der Basis-Task-Ebene aus durchgeführt werden, wo Sie alles tun können.

+0

Ich würde * stark * empfehlen gegen 'siglongjmp()' in eine 'sigjmp_buf' zu übersetzen, die von einem anderen Thread' sigsetjmp() 'erzeugt wird. – EOF

+0

Aber, nach pthread_sigmask (SIG_SETMASK, & Omask, NULL), würde ich noch den Signal-Handler für die ausstehenden Signale aufrufen? oder müssen sie noch einmal angerufen werden ?? – falhumai

+0

@EOF Natürlich. Meine erste Zeile war über das Blockieren von Signalen in allen außer _one_ thread [und das ist, wo die 'sigsetjmp/siglongjmp 'getan werden würde]. Und ich sagte: "Einen Thread für die Signalverarbeitung dedizieren und _it_ do sigsetjmp haben und der Signal-Handler siglongjmp". Persönlich bevorzuge ich den volatilen globalen [oder äquivalenten] Ansatz. –

2

Sie benötigen zwei Sperren. Der eine, der in Ihrem func() verwendet wird, und einer, um die Signalmaske des Prozesses zu schützen.

Sie müssen dafür Maskierung und Demaskierung das Signal Atom auch:

static pthread_mutex_t mask_mutex = PTHREAD_MUTEX_INITIALIZER; 
sigset_t old_set; 
sigset_t new_set; 

sigemptyset(&new_set); 
sigaddset(&new_set, SIGINT); 

pthread_mutex_lock(&mask_mutex); 

pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask); 

func(); 

pthread_sigmask(SIG_SETMASK, &old_mask, NULL); 

pthread_mutex_unlock(&mask_mutex); 

Ohne Sperre um die pthread_sigmask(), sind Fäden wahrscheinlich korrupt den Prozess sigmask als Ausführung überlappt.

+0

Was ist, wenn ein Signal vor pthread_sigmask (SIG_BLOCK, & new_mask, & old_mask) und nach pthread_mutex_lock aufgerufen wird (& mask_mutex)? Dann hätten wir einen Stillstand, oder? Was, wenn wir den Operationsauftrag änderten? – falhumai

+0

@falhumai Nein, weil es nicht derselbe Mutex ist. Wenn ein Signal gesendet wird, nachdem der Mutex, der die Aufrufe von 'pthread_sigmask()' schützt, gesperrt ist, kann der Thread, der diesen Mutex * gesperrt hat, den Mutex noch nicht in 'func()' speichern. * Zwischen den beiden 'pthread_sigmask()' Aufrufen 'func()' ist * de facto * kein Signal-Handler und kann daher sicher aufgerufen werden. Der zweite Mutex wird benötigt, um die Aufrufe von 'pthread_sigmask()' zu schützen und eine konsistente Signalmaske für den Prozeß aufrechtzuerhalten. –

-1

Sie können die Test Mutex Funktionen (Trylock) in dieser Art von undefinierten Situationen, um sicher zu sein. Und damit müssen Sie nicht unbedingt auch blocken.