1
votes

Comment attendre un signal pendant un certain temps seulement, en langage C?

J'essaie de communiquer entre 2 processus (processus parent et enfant sous Linux) en utilisant des signaux en langage de programmation C.

Le premier processus effectue des calculs et fournit des données. Ensuite, il envoie un signal au second, qui est dans un état suspendu , en attendant qu'un signal se réveille et collecte les données partagées par le premier processus à l'aide d'une mémoire partagée.

Comment faire attendre le deuxième processus pendant un certain temps ou disons une période de temps?

Dans cette période, si le premier processus fournit des données et envoie un signal au second, tout va bien. Sinon, s'il ne reçoit aucun signal du premier pendant cette période, il fera autre chose.

Comment puis-je faire en sorte que le deuxième processus réponde à ce besoin?

Quels algorithmes et signaux dois-je utiliser pour mettre en œuvre cela?


11 commentaires

sans aucune information sur la plate-forme cible, cette question ne peut pas recevoir de réponse satisfaisante


Il peut être plus simple d'utiliser des threads et un sémaphore.


Pour les processus, je les ai déjà mis en œuvre, j'ai toujours un problème avec le temps, comment faire attendre un processus enfant pour le signal dans un certain laps de temps en sachant qu'il est à l'état suspendu.


sigtimedwait () en est un approche possible.


Utilisez select pour ce faire.


@Shawn, oui peut-être que c'est une solution, je vais essayer de suivre cette voie et voir ce que je peux faire. Merci


@stark, je ne comprends pas vraiment de quoi vous parlez? pourriez-vous s'il vous plaît être plus précis?


La sélection sans descripteur de fichier attend un délai d'expiration ou un signal stackoverflow.com/a/52310127/1216776


Pourquoi utilisez-vous des signaux pour cela? C'est inutilement compliqué. select a une option de délai d'expiration. Le plus simple serait d'envoyer les données via un tube plutôt qu'avec de la mémoire partagée. Si vous souhaitez utiliser la mémoire partagée, envoyez simplement un octet par le canal au lieu d'envoyer un signal. Si vous voulez vraiment utiliser un signal, utilisez quelque chose comme signalfd . Dans les deux cas, utilisez toujours select pour le délai d'expiration.


@stark, j'ai essayé d'utiliser select mais je ne sais pas comment l'initialiser. Que dois-je mettre comme paramètres pour attendre le signal de peur de dire SIGUSER1 pendant 10 secondes. Quels sont les paramètres dois-je entrer pour l'initialiser?


Voir la réponse ci-dessous pour un exemple.


3 Réponses :


-1
votes

Vous pouvez inclure le premier processus de votre code dans une boucle while infinie (par exemple, while (1) {}) et une fois que les données calculées par le premier processus utilisent des fonctions pour envoyer des données au deuxième processus. Dans le deuxième processus, utilisez la fonction sleep (). Par exemple;

main()
{
   printf("Sleep for 10 milisecond to exit.\n");
   sleep(0.10);
   return ;
}
you may change the time.


0 commentaires

1
votes

Appel pour dormir jusqu'à 10 secondes ou le signal serait:

struct timeval t = {10, 0};
int rc = select(0, NULL, NULL, NULL, &t);
if (rc == 0) {
    // timeout
} else if (errno == EINTR) {
    // signal
} else {
    // some error


8 commentaires

J'ai ceci: erreur: expression attendue avant le jeton «{» int rc = select (0, NULL, NULL, NULL, {5, 0});


Avez-vous corrigé les avertissements? Ajoutez #include et #include


Que se passe-t-il si le signal arrive avant l'appel à select ? Est-ce que le PO manque un signal et l'expiration complète du délai?


@stark, j'ai toujours le même problème même après avoir inclus 2 bibliothèques


@pilcrow, je n'ai pas vraiment compris ce que j'ai dit, désolé.


@Gismail, c'est comme le problème de en utilisant pause < / code> pour attendre un signal . Si le signal arrive avant que votre code n'entre dans le select , alors votre code expirera, sans jamais savoir qu'il a été chargé de faire quelque chose.


@stark qu'est-ce que c'est: (errno == EINTR), parce qu'ils ne sont pas définis?


Toute la bibliothèque système contient une documentation qui vous indique quels fichiers d'en-tête système vous devez inclure pour les définir. Veuillez apprendre à le rechercher par vous-même car c'est une compétence nécessaire.



2
votes

POSIX définit une fonction exactement pour vos besoins: sigtimedwait () . Il suspendra l'exécution du processus appelant jusqu'à ce que soit l'un des signaux d'un ensemble spécifié devienne en attente, ou qu'un délai spécifié expire. Sa valeur de retour indique laquelle de celles-ci s'est produite.

Dans cette période, si le premier processus fournit des données et envoie un signal au second, tout va bien. Sinon, s'il ne reçoit aucun signal du premier pendant cette période, il fera autre chose.

Comment puis-je faire en sorte que le deuxième processus réponde à ce besoin?

Le deuxième processus configure les arguments pour sigtimedwait . Il bloque ensuite le signal attendu (via sigprocmask ), afin que la disposition par défaut ne se produise pas lorsque ce signal est reçu, et appelle ensuite sigtimedwait . La valeur de retour de ce dernier indique si l'un des signaux spécifiés a été reçu (et si oui, lesquels), ou si la fonction est retournée pour une autre raison - généralement parce que le délai a expiré. Dans ce dernier cas, la variable errno peut être examinée pour déterminer s'il s'agissait bien d'un timeout. La page de manuel liée ci-dessus fournit quelques notes d'utilisation supplémentaires.

Plus précisément, vous avez besoin de deux arguments principaux:

  • un sigset_t définissant les signaux à bloquer et à attendre. La section «Voir aussi» à la fin de la page de manuel vous renvoie à la documentation des fonctions associées et similaires, y compris sigsetops (3) , qui vous explique comment manipuler de tels objets. Par exemple,

        if (errno == EAGAIN) {
            // it was a timeout
        } else if (errno = EINTR) {
            // a signal outside the set was received
            // ... might want to calculate how much wait time is left and try again
            //     (left as an exercise)
        } else {
            // some other error occurred
            // ... aborting with an error might be best:
            perror("signal wait failed unexpectedly");
            exit(1);
        }
    
  • une struct timespec , dont la définition est fournie en ligne dans la page de manuel. Cette définition devrait être suffisante pour que vous trouviez quelque chose comme

    if (sig_num == SIGUSER2) {
        // I received the signal
        // do something ...
    } else {
        // assert(sig_num == -1);
        // I did not receive the signal within the alotted time
        // do something else ...
    }
    

Selon la documentation, vous pouvez spécifier le deuxième argument de sigtimedwait comme NULL si vous n'avez pas besoin des informations qui autrement pourraient vous être renvoyées par ce moyen, ce que vous ne faites pas.

Vous pouvez utiliser l'ensemble de signaux déjà préparé comme décrit ci-dessus pour configurer le blocage de signal, par exemple:

int sig_num = sigtimedwait(&sigs, NULL, &timeout);

Cela peut sembler un peu contre-intuitif, car vous voulez recevoir le signal, mais l'effet est d'empêcher toute disposition établie pour le signal de se produire, ce qui est un chemin différent de sa gestion via sigtimedwait code>.

À ce stade, vous êtes prêt à appeler sigtimedwait():

sigprocmask(SIG_BLOCK, &sigs, NULL);

Le résultat sera un numéro de signal si l'un des signaux spécifiés (uniquement SIGUSER2 dans cet exemple) est reçu dans le délai spécifié, ou -1 dans le cas contraire. Par conséquent,

struct timespec timeout = { .tv_sec = 10 };

Vous pouvez choisir de supposer qu'un délai d'attente s'est produit dans le cas où le signal n'est pas reçu, mais le code le plus robuste vérifierait errno code > pour vérifier que:

#include <signal.h>

// ...

sigset_t sigs;
sigemptyset(&sigs);
sigaddset(&sigs, SIGUSER2);


4 commentaires

J'ai essayé de suivre l'explication sur la page de manuel, mais il m'est impossible de suivre les instructions.Tout ce dont j'ai besoin, c'est d'attendre un signal SIGUSER2 du premier dans les 10 secondes.Je ne sais pas comment mettre en œuvre cela.


@Gismail, lire de la documentation telle que la page de manuel que j'ai liée est une compétence importante que vous devrez absolument apprendre si vous voulez être un programmeur efficace. Mais cela peut être un peu intimidant au début, surtout si vous n'êtes pas bien familiarisé avec la langue au départ. J'ai ajouté des commentaires substantiels et des exemples de code qui, je l'espère, aideront dans ce cas.


Je mentionnerais également que les signaux attendus doivent être bloqués avant d'appeler sigtimedwait . C'est peut-être ce que vous vouliez dire en faisant référence à "quelques notes d'utilisation supplémentaires" dans la page de manuel, mais je suggère que c'est assez important pour être appelé ici.


Assez juste, @pilcrow, j'ai étendu mes commentaires et mon exemple de code pour aborder explicitement le blocage de signal nécessaire.