Quelle est la différence entre sigaction et signal?

j'étais sur le point d'ajouter un gestionnaire de signal pour une application que nous avons ici et j'ai remarqué que l'auteur avait utilisé sigaction pour configurer les autres gestionnaires de signaux. J'allais à l'utilisation du signal. Pour suivre la convention, je devrais utiliser sigaction mais si j'écrivais à partir de zéro, Que devrais-je choisir?

113
demandé sur Good Person 2008-10-24 03:15:14

8 réponses

utilisez sigaction() sauf si vous avez des raisons très convaincantes de ne pas le faire.

l'interface signal() a l'Antiquité (et donc la disponibilité) en sa faveur, et elle est définie dans la norme C. Néanmoins, il a un certain nombre de caractéristiques indésirables que sigaction() évite-sauf si vous utilisez les drapeaux explicitement ajoutés à sigaction() pour lui permettre de simuler fidèlement l'ancienne signal() comportement.

  1. la fonction signal() ne bloque pas (nécessairement) les autres signaux à l'arrivée pendant l'exécution du gestionnaire de courant; sigaction() peut bloquer d'autres signaux jusqu'au retour du gestionnaire de courant.
  2. la fonction signal() rétablit (habituellement) l'action du signal à SIG_DFL (par défaut) pour presque tous les signaux. Cela signifie que le gestionnaire signal() doit se réinstaller comme sa première action. Il ouvre également up fenêtre de vulnérabilité entre le moment où le signal est détecté et celui où le handler est réinstallé.si une seconde instance du signal arrive, le comportement par défaut (généralement se termine, parfois avec un dump de type prejudice - alias core) se produit.
  3. le comportement exact de signal() varie selon les systèmes - et les normes autorisent ces variations.

ce sont généralement de bonnes raisons d'utiliser sigaction() au lieu de signal() . Cependant, l'interface de sigaction() est indéniablement plus délicat.

quelle que soit la solution que vous utilisez, ne vous laissez pas tenter par les interfaces de signaux alternatives telles que: sighold() , sigignore() , sigpause() et sigrelse() . Ils sont nominalement des alternatives à sigaction() , mais ils sont à peine standardisés et sont présents en POSIX pour la rétrocompatibilité plutôt que pour un usage sérieux. Notez que la norme POSIX indique que leur comportement dans les programmes multi-threads n'est pas défini.

Multi-threaded des programmes et des signaux est une toute autre histoire compliquée. AFAIK, les deux signal() et sigaction() sont OK dans les applications multi-threaded.

les tiges de maïs observe :

la page de manuel de Linux pour signal() dit:

   les effets de signal() dans un procédé multi-filetés ne sont pas spécifiés.

Donc, je pense que sigaction() est le seul qui peut être utilisé en toute sécurité dans un processus multithread.

c'est intéressant. La page de manuel Linux est plus restrictive que POSIX dans ce cas. POSIX spécifie pour signal() :

si le processus est multi-threadé, ou si le processus est monofiltre et qu'un gestionnaire de signal est exécuté autrement que comme résultat de:

  • le processus appelant abort() , raise() , kill() , pthread_kill() , ou sigqueue() pour générer un signal qui n'est pas bloqué
  • en attente signal étant débloqué et livré avant l'appel qui l'a débloqué il retourne

le comportement n'est pas défini si le gestionnaire de signal se réfère à un objet autre que errno avec une durée de stockage statique autre qu'en assignant une valeur à un objet déclaré comme volatile sig_atomic_t , ou si le gestionnaire de signal appelle une fonction définie dans la présente norme autre qu'une des fonctions énumérées dans concepts de Signal .

ainsi POSIX spécifie clairement le comportement de signal() dans une application multi-threadée.

néanmoins, sigaction() doit être préféré dans essentiellement toutes les circonstances - et le code portable multi-threadé devrait utiliser sigaction() à moins qu'il n'y ait une raison écrasante pourquoi il ne peut pas (comme" utiliser uniquement des fonctions définies par la norme C " - et oui, le code C11 peut être multi-threadé). Qui est essentiellement ce que le premier paragraphe de cette réponse dit aussi.

140
répondu Jonathan Leffler 2017-05-23 12:02:29

ce sont des interfaces différentes pour les installations de signalisation du système D'exploitation. On devrait préférer utiliser sigaction pour signaler si possible que le signal () a un comportement implémenté (souvent enclin à la course) et se comporte différemment sur Windows, OS X, Linux et D'autres systèmes UNIX.

voir cette note de sécurité pour plus de détails.

5
répondu ididak 2008-10-24 00:24:49

pour moi, cette ligne ci-dessous était suffisante pour décider:

la fonction sigaction () fournit plus complet et fiable mécanisme de commande des signaux; nouveau les applications doivent utiliser sigaction() plutôt que signal ()

http://pubs.opengroup.org/onlinepubs/009695399/functions/signal.html#tag_03_690_07

que vous partiez de zéro ou modifier un ancien programme, sigaction devrait être la bonne option.

4
répondu San 2011-07-03 06:24:08

De la signal(3) l'homme page:

DESCRIPTION

 This signal() facility is a simplified interface to the more
 general sigaction(2) facility.

invoquent tous deux la même facilité sous-jacente. Vous ne devriez probablement pas manipuler la réponse d'un seul signal avec les deux, mais les mélanger ne devrait pas causer de rupture...

2
répondu dmckee 2008-10-23 23:26:09

j'utiliserais signal() car il est plus portable, en théorie du moins. Je voterai pour tout commentateur qui peut proposer un système moderne qui n'a pas de couche de compatibilité POSIX et supporte signal().

citant le glibc documentation :

il est possible d'utiliser à la fois les fonctions signal et sigaction un seul programme, mais vous devez être prudent, car ils peuvent interagir dans des façons un peu étranges.

la fonction sigaction spécifie plus d'informations que le signal fonction, de sorte que la valeur de retour du signal ne peut pas exprimer la pleine gamme de possibilités de sigaction. Par conséquent, si vous utilisez le signal sauver et plus tard rétablir une action, il peut ne pas être en mesure de rétablir correctement un handler qui a été établi avec sigaction.

pour éviter d'avoir des problèmes en conséquence, utilisez toujours sigaction pour enregistrer et restaurer un gestionnaire si votre programme utilise sigaction. Depuis sigaction est plus général, il peut enregistrer correctement et rétablir n'importe quel d'action, indépendamment du fait qu'elle ait été établie à l'origine avec signal ou sigaction.

sur certains systèmes si vous établissez une action avec signal et puis examinez-le avec sigaction, l'adresse du Gestionnaire que vous obtenez peut ne pas soyez le même que ce que vous avez spécifié avec signal. Il peut même ne pas être utilisable comme argument d'action avec le signal. Mais vous pouvez compter en l'utilisant comme argument pour sigaction. Ce problème n'arrive jamais sur le système GNU.

donc, il vaut mieux utiliser l'un ou l'autre des mécanismes de façon constante au sein d'un même programme.

portabilité Note: la fonction de signal de base est une caractéristique de L'ISO C, alors que sigaction fait partie du POSIX.1 standard. Si vous êtes soucieux de la portabilité vers des systèmes non-POSIX, alors vous devriez l'utilisation de la la fonction de signal à la place.

Copyright (C) 1996-2008 Free Software Foundation, Inc.

Permission est accordée pour copier, distribuer et/ou modifier document sous les termes de la licence de Documentation Libre GNU, Version 1.2 ou toute version ultérieure publiée par le Logiciel Libre Fondation; sans sections invariantes, sans Textes De Couverture, et des Textes. Une copie de la licence est inclus dans la section intitulée "GNU Free Documentation License".

2
répondu bmdhacks 2008-10-23 23:27:23

signal() est standard C, sigaction () ne l'est pas.

si vous êtes capable d'utiliser l'un ou l'autre (c'est-à-dire que vous êtes sur un système POSIX), utilisez alors sigaction(); il n'est pas spécifié si signal() réinitialise le Gestionnaire, ce qui signifie que pour être portable vous devez appeler signal() à nouveau à l'intérieur du gestionnaire. Ce qui est pire, c'est qu'il y a une course: si vous recevez deux signaux en succession rapide, et que le second est livré avant de réinstaller le Gestionnaire, vous aurez l'action par défaut, qui est ce sera sûrement pour tuer ton processus. sigaction () , d'autre part, est garanti d'utiliser une sémantique de signal "fiable". Vous n'avez pas besoin de réinstaller le gestionnaire, car il ne sera jamais réinitialiser. Avec SA_RESTART, vous pouvez également obtenir certains appels système pour redémarrer automatiquement (de sorte que vous n'avez pas à vérifier manuellement pour EINTR). sigaction () a plus d'options et est fiable, donc son utilisation est encouragée.

Psst... ne le dites à personne, je je vous l'ai dit, mais POSIX a actuellement une fonction bsd_signal() qui agit comme signal () mais qui donne une sémantique BSD, ce qui signifie qu'elle est fiable. Son utilisation principale est de porter des applications anciennes qui supposaient des signaux fiables, et POSIX ne recommande pas de l'utiliser.

2
répondu Huzzefakhan 2014-05-23 07:05:37

je suggère aussi d'utiliser sigaction() au-dessus de signal() et je voudrais ajouter un point supplémentaire. sigaction () vous donne plus d'options telles que pid du processus mort (possible en utilisant la structure siginfo_t).

1
répondu pradyumna kaushik 2016-03-09 06:49:06

De l'homme, la page signal(7)

un signal de procédé peut être livré à n'importe quel un des threads qui n'a pas actuellement le signal bloqué. Si plus d'un des fils a le signal débloqué, alors le le noyau choisit un thread arbitraire pour délivrer le signal.

Et je dirais que ce "problème" existe pour signal(2) et sigaction (2) . Alors faites attention avec les signaux et les pthreads.

... et signal (2) semble appeler sigaction(2) ci-dessous sous Linux avec glibc.

0
répondu robert.berger 2018-09-05 08:31:29