2016-07-11 1 views
1

Si j'ai un programme comme celui-ci (en pseudocode):Y at-il un moyen d'assurer l'atomicité tout en ayant un programme multithread avec des gestionnaires de signaux?

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(); 
} 

alors il y aurait une impasse lors de la tentative d'acquérir le verrou Func, alors qu'il est déjà acquis de l'appelant « principal ». Je me demandais s'il y avait un moyen de suspendre la gestion du signal dans le langage C, spécifiquement, quand, dans cet exemple, entrer func et acquérir le verrou, et reprendre la gestion du signal ET appeler les gestionnaires à la sortie func.

+0

L'interaction entre les threads et la gestion des signaux dans C lui-même n'est pas définie. Tu dois être plus précis. Votre système est-il un système POSIX? Veuillez marquer votre question en conséquence. –

Répondre

2

Vous voulez pthread_sigmask, la version multithread de sigprocmask

est ici un code pseudo exemple:

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 ... 
} 

Je ne suis pas tout à fait sûr, mais, vous devrez peut-être utiliser pthread_sigmask pour bloquer les signaux dans tous les mais un thread et faire ce qui précède à partir de ce fil uniquement.

Aussi, je m'en voudrais de ne pas dire que je refactoriserais votre code. Le nombre de choses que vous pouvez faire dans un gestionnaire de signaux [en dehors de cette] est limitée (par exemple, pas malloc, pas printf, etc.)

Consacrer un fil pour le traitement du signal et de l'avoir fait sigsetjmp et le gestionnaire de signal ne siglongjmp .

Ou de demander au gestionnaire de signaux de définir une valeur globale volatile (par exemple signal_occurred) surveillée au niveau de base.

Ainsi, tous les "gros travaux" que vous feriez dans le gestionnaire de signaux peuvent être effectués à partir du niveau de la tâche de base où vous pouvez faire n'importe quoi.

+0

Je recommanderais fortement de ne pas utiliser siglongjmp() dans un 'sigjmp_buf' créé par un autre thread' sigsetjmp() '. – EOF

+0

Mais, après pthread_sigmask (SIG_SETMASK, & omask, NULL), est-ce que j'appellerais toujours le gestionnaire de signal pour les signaux en attente ?? ou ils doivent être appelés une fois de plus ?? – falhumai

+0

@EOF Bien sûr. Ma première ligne concernait le blocage des signaux dans tous les threads sauf un [et c'est là que le 'sigsetjmp/siglongjmp' serait fait]. Et j'ai dit: "Consacrer un thread pour la gestion du signal et avoir _it_ do sigsetjmp et le gestionnaire de signal siglongjmp". Personnellement, je préfère [et j'ai utilisé] l'approche globale [ou équivalente] volatile. –

2

Vous avez besoin de deux verrous. Celui utilisé à l'intérieur de votre func(), et un pour protéger le masque de signal du processus.

Vous devez faire masquer et démasquer le signal atomique aussi:

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); 

sans verrou autour du pthread_sigmask(), les fils sont probablement le processus sigmask que l'exécution chevauche la corruption.

+0

Que faire si un signal est appelé avant pthread_sigmask (SIG_BLOCK, & new_mask, & old_mask), et après pthread_mutex_lock (& mask_mutex)? Ensuite, nous aurions une impasse, non? Et si nous passions l'ordre des opérations? – falhumai

+0

@falhumai Non, parce que ce n'est pas le même mutex. Si un signal est délivré après que le mutex protégeant les appels 'pthread_sigmask()' est verrouillé, le thread qui a verrouillé ce mutex * ne peut pas contenir le mutex dans 'func()'. * Entre les deux appels 'pthread_sigmask()', 'func()' est * de facto * pas un gestionnaire de signal et peut donc être appelé en toute sécurité. Le second mutex est nécessaire pour protéger les appels 'pthread_sigmask()' et maintenir un masque de signal cohérent pour le processus. –

-1

Vous pouvez utiliser les fonctions test mutex (trylock) dans ce genre de situations non définies, pour être sûr. Et avec cela, vous n'avez pas nécessairement besoin de bloquer aussi.