Simple Linux De Traitement De Signal
J'ai un programme qui crée de nombreux fils et s'exécute jusqu'à ce que l'alimentation est l'arrêt de l'ordinateur, ou si l'utilisateur utilise kill
ou ctrlc pour terminer le processus.
Voici un peu de code et comment le main() regarde.
static int terminate = 0; //does this need to be volatile?
static void sighandler(int signum) { terminate = 1; }
int main() {
signal(SIGINT, sighandler);
//...
//create objects, spawn threads + allocate dynamic memory
//...
while (!terminate) sleep(2);
//...
//clean up memory, close threads, etc.
//...
signal(SIGINT, SIG_DFL); //is this necessary?
}
Je me demandais un peu les choses:
-
Est un signal de manutention nécessaires?
J'ai lu dans ce fil "Linux C capture de signal kill pour un arrêt progressif", qui, apparemment, le système d'exploitation de la poignée de nettoyage pour moi.
Donc, puis-je remplacer le gestionnaire de signal avec juste une boucle infinie et de laisser l'OS gracieusement sortie le fils, de-allouer de la mémoire, etc? -
Il d'autres signaux que j'ai besoin d'être concernés par un sujet propre à la résiliation? Ce fil "Comment ne SIGINT se rapportent à l'autre de la résiliation des signaux?", a été utile à la liste de tous les signaux que j'ai peut-être concerné, mais combien réellement nécessaire de manutention?
-
Ne le résilier variable dans mon exemple être volatile? J'ai vu de nombreux exemples où cette variable est volatile, et d'autres où elle ne l'est pas.
-
J'ai lu que
signal()
est maintenant obsolète, et d'utilisersigaction()
. Sont-il vraiment de bons exemples pour montrer comment convertir de la précédentesignal()
appel? Je vais avoir des ennuis avec la nouvelle structure que j'ai créer/transmettre et comment il s'adapte à tous ensemble. -
Est le deuxième appel à
signal()
nécessaire?
Est-il quelque chose de similaire que j'ai besoin d'être concernés, avec poursigaction()
?
Pour être clair, tout ce que je suis en train d'accomplir pour avoir mon: boucle principale d'exécuter jusqu'à ce que ctrlc ou d'alimentation est débranché ou quelque chose de vraiment mauvais.
- À propos de les nettoyer, il est à nettoyer que le système ne peut pas le faire. Un exemple est si vous communiquent via un port série, alors vous pourriez avoir besoin d'envoyer un "au revoir" message pour dire à l'autre extrémité vous allez loin.
- Oui, mais n'est-ce pas un peu une méthode peu fiable de dire à l'autre fin que j'ai disparu? Par exemple, si SIGKILL frappe le processus, il n'y a rien que je peux faire ou pas de gestionnaire que je peux mettre en place, car aucun gestionnaire peut être mappé à un SIGKILL... Pour certaines applications, mais je peux voir pourquoi c'est utile. Pour le mien, j'ai juste besoin de faire mémoire de l'allocation et de la fermeture de certains threads.
- Vous n'êtes pas obligé de faire de signal handeling, mais il peut être très ennuyeux, si vous avez un 5 étape 10 minutes par pas de programme de calcul par exemple. L'utilisateur peut accidentellement tuer le programme. Si un signal handeling pourrait enregistrer les résultats intermédiaires à partir des étapes 1 à 4, lorsqu'il est tué.
- qui vous suggérons d'appeler
signal(SIGINT, SIG_DFL);
dans main()? de référence ?
Vous devez vous connecter pour publier un commentaire.
Le drapeau
terminate
devrait êtrevolatile sig_atomic_t
:Parce que les fonctions du gestionnaire peut être appelée de façon asynchrone. C'est, un gestionnaire pourrait être appelé à tout moment dans le programme, de façon imprévisible. Si deux signaux arrivent pendant un intervalle très court, un gestionnaire peut s'exécuter à l'intérieur de l'autre. Et il est considéré comme une meilleure pratique de déclarer
volatile sig_atomic_t
, ce type sont toujours accessibles de façon atomique, d'éviter toute incertitude à propos d'interrompre l'accès à une variable.volatile
indique au compilateur de ne pas l'optimiser et de le mettre dans le registre. (lire: Atomique d'Accès aux Données et traitement du Signal pour le détail de l'expiation).Encore une référence: 24.4.7 Atomique d'Accès aux Données et traitement du Signal.
En outre, la norme C11 dans 7.14.1.1-5 indique que seuls les objets de
volatile sig_atomic_t
peut être accessible à partir d'un gestionnaire de signal (l'accès à d'autres, a un comportement indéfini).L'exemple ci-dessous (et le lien dans les commentaires) peut être utile:
références:
sigaction()
bien dans le "Chapitre 11: les Processus et Signaux".*j'ai commencé à partir de Un, Actuellement, je fais de la lecture Trois GNU library
Pourquoi vous pouvez définir la valeur par défaut, l'action avant la fin du programme n'est pas clair pour moi. Je pense que le paragraphe suivant vous donnera une réponse:
La
signal()
la fonction qui définit le gestionnaire de la prochaine signal reçu seulement, après lequel le gestionnaire par défaut est rétabli. Il est donc nécessaire pour le gestionnaire de signal pour appelersignal()
si le programme doit continuer la manipulation des signaux à l'aide d'un non-gestionnaire par défaut.Lire une discussion à titre de référence: Lors de la ré-activer les gestionnaires de signaux.
Oui, Linux va faire le nettoyage pour vous. Par exemple, si vous n'avez pas la fermeture d'un fichier ou d'un socket, Linux va faire le nettoyage après la fin du processus. Mais Linux ne peut pas nécessaire d'effectuer le nettoyer immédiatement et il peut prendre un certain temps (peut-être de garder les performances du système de haut ou de certaines autres questions). Par exemple, si vous ne fermez pas un tcp socket, et le programme se termine le noyau ne sera pas fermer le socket immédiatement afin de s'assurer que toutes les données ont été transmises, TCP garantit la livraison si possible.
Pas, le système d'exploitation n'effectue de nettoyage seulement après le programme se termine. Tout un processus s'exécute, les ressources qui sont allouées à ce processus n'obtenez pas revendiquée par le système d'exploitation. (Le système d'exploitation ne peut pas savoir si votre processus est dans une boucle infinie ou pas - c'est un problème insoluble). Si vous voulez que, après la fin du processus le système d'exploitation effectue les opérations de nettoyage pour vous, alors vous n'avez pas besoin de traiter les signaux (même dans le cas où votre processus anormalement termine par un signal).
Non, il y a une limite! Vous ne pouvez pas attraper tous les signaux. Certains signaux ne sont pas catchable par exemple
SIGKILL
etSIGSTOP
et les deux sont à la résiliation des signaux. Citant:De sorte que vous ne pouvez pas faire un programme qui ne peut pas être interrompu (une interruption de programme)!
Je ne suis pas sûr, mais peut-être vous pouvez faire quelque chose comme cela dans les systèmes Windows: par l'écriture de programmes Résidents (une sorte de noyau de mode d'accrochage). Je me souviens de ma thèse temps que certains virus ne pouvait pas être terminé, même dans le gestionnaire des tâches, mais je pense aussi qu'ils tromper l'utilisateur en autorisations d'administration.
J'espère que cette réponse vous aidera.
sigemptyset(&sa.sa_mask)
, sinon son contenu ne sont pas initialisées. (aussi, vous n'avez pas besoin d'une autre variable pour l'ensemble)Pour l'utilisation de
sigaction
au lieu de cela, vous pouvez utiliser une fonction comme ceci:D'abord, jetez un coup d'oeil à sa page : La GNU Library Signaux
La résiliation des signaux est ce que vous en occuper. Mais jetez un oeil à SIGUSR1 et SIGUSR2, même si vous 'll jamais les trouver dans n'importe quel logiciel, sauf à des fins de débogage.
Tous de cette résiliation signaux doivent être traitées si vous ne voulez pas que votre soft de résilier tout d'un coup.
Sigaction()
est POSIX alors que le signal est un C standard.Signal()
fonctionne très bien pour moi, mais si vous voulez un exemple : Exemple d'IBMIl n'est pas nécessaire d'utiliser des signaux pour cela. Un standard de mettre fin à ne pas besoin d'être pris. Vous pouvez avoir des raisons pour l'attraper, mais qui serait en bas de votre application, plutôt que tout ce qui est requis par l'O/S.
En termes de signaux, en général, vous devez utiliser sigaction pas de signal de ces jours, il reçoit autour d'une normalisation question.
Les gestionnaires de signaux doit être écrit pour être réentrant. Cela ne nécessite pas de résilier votre variable volatile, mais il peut, selon la façon dont vous l'utiliser!
Le W. Richard Stevens livre "Advanced Programming in the UNIX Environment" a un bon exemple de pourquoi et comment traiter les signaux.
Et non, vous n'avez pas à remettre le gestionnaire par défaut avant que votre application se termine, votre gestionnaire est seulement valide pour votre application, donc si vous êtes simplement à la mise à mort de l'application, il n'est pas nécessaire.
Tout d'abord - si vous ne savez pas, si vous devez gérer tous les signaux, alors vous n'avez probablement pas. Les signaux nécessitent un traitement dans certains cas spécifiques, comme la fermeture de sockets, l'envoi d'un message à d'autres processus avant de quitter, ou de la manipulation de SIGNAL signal d'écriture() (et probablement beaucoup plus).
D'autre part - ce
while (!terminate) sleep(2);
n'est pas très bonne dans le pire des cas, il peut faire l'utilisateur (ou le même système) impatient d'avoir à attendre 2s et l'envoyer à votre programme un SIGKILL, que vous ne pouvez pas gérer.À mon humble avis la meilleure solution serait ici à l'aide de signalfd et sélectionnez, de sorte que vous pouvez mettre fin à votre programme sans avoir à attendre 2s.