8
votes

Comment mettre fin à un fil de couchage dans Pthread?

J'ai le fil qui dort pendant une longue période, puis se réveille pour faire quelque chose, puis dormir à nouveau, comme ceci: xxx

Comment puis-je sortir de ce fil gracieusement et rapidement? < / p>

J'ai essayé d'utiliser pthread_cancel () , mais les fils de couchage n'ont pas pu être annulés. J'ai également essayé de changer l'état de la boucle tandis que la boucle, mais cela va toujours prendre longtemps à la sortie. Et je ne veux pas utiliser pthread_kill () , car il peut tuer le fil quand il fonctionne.

Alors, y a-t-il de bonnes idées?


3 commentaires

Eh bien, je pense que je fais une erreur, dormir () est un point d'annulation défini par POSIX.1


Juste une note - pthread_kill ne tue pas un fil. Il envoie un signal à un fil. Si l'action de ce signal doit résilier le processus (par exemple, l'action par défaut de sigterm ou l'action non bloquée de sigkill ), il terminera tout le processus , pas le fil cible. Vraiment la seule fois pthread_kill est utile, c'est si vous avez installé un gestionnaire de signal d'interruption et que vous souhaitez interrompre un système SYSCALL qui est bloqué dans un thread particulier (qui serait une solution potentielle à votre question).


Pourquoi avez-vous dit que le fil ne pouvait pas quitter rapidement? J'ai essayé cela et le fil annulé immédiatement sur thread_cancel . Et j'ai pu pthread_join sans délai.


3 Réponses :


11
votes

comme alternative à dormir , vous pouvez utiliser pthread_cond_timedwait avec un temporisateur de 1000 ms. Ensuite, lorsque vous souhaitez quitter, signalez la variable de condition.

Ceci est similaire à la manière dont vous pourriez le faire en C # / Java à l'aide d'attendre et de notifier.


4 commentaires

Correct. C'est le moyen simple et non racé de le faire.


Ceci est correct, mais l'annulation est plus facile et peut-être légèrement plus efficace. Bien sûr, si vous appelez pthread_cancel sur le thread, vous devez vous assurer qu'il ne peut pas être annulé à un moment de cela. Appelant pthread_setcancelstate Pour désactiver l'annulation Lorsque le thread démarre, et ne le permettant que juste avant la veille , serait une approche sécurisée.


Imo, pthread_cancel () peut être préférable car Sleep () est déjà un point d'annulation. Et assurez-vous d'appeler pthread_cleanup_push () et pthread_cleanup_pop () Pour configurer les gestionnaires de nettoyage si vous avez alloué des ressources.


Quelle est la différence entre utiliser pthread_cond_timpedwait avec un délai d'attente de 1000 ms et utiliser une variable de drapeau avec 100 ms de sommeil en ce qui concerne la condition de course?



0
votes

La variable classique Unix condition est le auto-pipe .

int fds[2];
pipe2(fds, O_NONBLOCK);  // requires newish kernel and glibc; use pipe + 2*fcntl otherwise

child:
    while (some_condition) {
        // do something
        struct pollfd pd = { .fd = fds[0], .events = POLLIN };
        int rc;
        char c;
        while ((rc = poll(&pd, 1, 1000000)) == -1 && errno == EINTR)
            // not entirely correct; 1000000 should be decreased according to elapsed time when repeating after a signal interruption
            ;
        if (rc > 0 && (pd.revents & POLLIN) && read(fds[0], &c, 1) >= 0)
            break;
    }

parent:
    cancel() {
        char c = 0;
        write(fds[1], &c, 1);
    }


0 commentaires

1
votes

Avez-vous utilisé pthread_cleanup_push et pop? L'annulation avec pthread_cancel ne fonctionne pas sans eux. Vous devez les utiliser par paires comme je l'ai fait dans l'exemple ci-dessous. Si vous oubliez un, il ne compilera pas (macros fantaisie, on a le '{' et l'autre a le '}'). Vous pouvez même nier différents niveaux de nettoyage / pop. Quoi qu'il en soit, ils définissent un long point de saut qui annule des sauts lors de l'annulation survient (assez cool). De plus, si votre programme de test n'attend pas que le thread commence ou s'arrête, vous ne remarquez peut-être pas l'annulation de l'annulation.

Exemple: P>

MAIN: waiting for thread to startup...
THREAD: Enter Sleep
MAIN: sending cancel...
MAIN: waiting for thread to exit...
THREAD: unwind (all threads, canceled or normal exit get here)
MAIN: done


3 commentaires

Vous pouvez utiliser pthread_cancel juste bien sans les gestionnaires de nettoyage, mais si vous avez alloué des ressources qui devraient être libérées, cela entraînerait une fuite de ressources.


Je suis sûr que vous avez raison quand il s'agit de ce sujet. J'avais déjà cru que CleanUp_Push et Pop configurent le Longjump que Pthread_Cancel a invoqué. Je suppose que vous dites que vous dites qu'il y a une configuration par défaut par pthread_create. Est-ce que je le fais bien?


À la fin de la chaîne des gestionnaires de nettoyage, le code de sortie du fil interne de mise en œuvre (qui inclut des destructeurs de données spécifiques à thread et éventuellement d'autres éléments spécifiques à la mise en œuvre). S'il n'y a pas de gestionnaires de nettoyage, l'exécution passe directement là-bas. L'annulation et un appel à pthread_exit par le fil lui-même ont cet effet.