Annulation des threads POSIX[

Ce forum est dédié à apprendre le développement de programmes user mode sur Linux

Moderator: Rick

Post Reply
Hydraxx
Site Admin
Posts: 54
Joined: Mon Jan 12, 2026 4:04 pm
Location: France
Contact:

Annulation des threads POSIX[

Post by Hydraxx »

Annulation des threads POSIX

Objectif du chapitre

Dans un programme multithread, il peut être nécessaire de demander à un thread de terminer avant qu’il ait fini son travail.

POSIX fournit pour cela un mécanisme d’annulation coopérative basé principalement sur :

Code: Select all

pthread_cancel()
pthread_setcancelstate()
pthread_setcanceltype()
pthread_testcancel()
pthread_cleanup_push()
pthread_cleanup_pop()
Il est important de comprendre qu’un appel à

Code: Select all

pthread_cancel()
ne tue pas forcément immédiatement le thread.

Il envoie une demande d’annulation.

Le moment où le thread se termine dépend ensuite :
  • de son état d’annulation ;
  • de son type d’annulation ;
  • de l’existence de points d’annulation ;
  • de la bonne libération de ses ressources.

1. Envoyer une demande d’annulation

La fonction utilisée pour demander l’annulation d’un thread est :

Code: Select all

#include <pthread.h>

int pthread_cancel(pthread_t thread);
Elle envoie une demande d’annulation au thread désigné par

Code: Select all

thread
.

Valeur de retour :
  • Code: Select all

    0
    en cas de succès ;
  • un numéro d’erreur positif en cas d’échec.
Exemple :

Code: Select all

pthread_t thread;

pthread_create(&thread, NULL, fonction_thread, NULL);

pthread_cancel(thread);
pthread_join(thread, NULL);
Le succès de

Code: Select all

pthread_cancel()
signifie seulement que la demande d’annulation a été envoyée.

Cela ne garantit pas encore que le thread est déjà terminé.

Le thread peut :
  • être annulé immédiatement ;
  • attendre d’atteindre un point d’annulation ;
  • conserver la demande en attente ;
  • ne jamais être annulé si l’annulation reste désactivée.

2. État d’annulation d’un thread

Chaque thread possède un état d’annulation.

Cet état détermine si une demande d’annulation peut être prise en compte.

La fonction correspondante est :

Code: Select all

#include <pthread.h>

int pthread_setcancelstate(int state, int *oldstate);
Le paramètre

Code: Select all

state
accepte deux valeurs principales.


PTHREAD_CANCEL_ENABLE

L’annulation est activée.

Une demande d’annulation peut être traitée selon le type d’annulation du thread.

C’est l’état par défaut d’un nouveau thread.


PTHREAD_CANCEL_DISABLE

L’annulation est désactivée.

Une demande envoyée avec

Code: Select all

pthread_cancel()
n’est pas perdue : elle reste en attente.

Elle pourra être traitée plus tard lorsque le thread réactivera l’annulation.


Le second paramètre,

Code: Select all

oldstate
, permet de récupérer l’ancien état.

Exemple :

Code: Select all

int ancien_etat;

pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &ancien_etat);

/* Section critique non annulable */

pthread_setcancelstate(ancien_etat, NULL);
Désactiver temporairement l’annulation est utile lorsqu’un thread modifie une structure partagée, manipule une ressource importante ou réalise plusieurs opérations qui doivent rester atomiques du point de vue logique.


3. Type d’annulation

Lorsque l’annulation est activée, le type d’annulation détermine quand la demande sera exécutée.

La fonction utilisée est :

Code: Select all

#include <pthread.h>

int pthread_setcanceltype(int type, int *oldtype);
Deux types existent.


PTHREAD_CANCEL_DEFERRED

L’annulation est différée.

La demande reste en attente jusqu’à ce que le thread atteigne un point d’annulation.

C’est le type par défaut.

C’est également le type recommandé dans la majorité des programmes.


PTHREAD_CANCEL_ASYNCHRONOUS

L’annulation est asynchrone.

Le thread peut être annulé presque à n’importe quel moment.

Ce mode est très dangereux, car le thread peut être interrompu :
  • pendant qu’il détient un mutex ;
  • pendant une allocation mémoire ;
  • pendant la modification d’une structure ;
  • entre deux instructions dépendantes ;
  • alors qu’un invariant interne est temporairement invalide.
Exemple de changement temporaire :

Code: Select all

int ancien_type;

pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &ancien_type);

/* Travail annulable uniquement aux points prévus */

pthread_setcanceltype(ancien_type, NULL);
Dans la pratique, il faut presque toujours conserver

Code: Select all

PTHREAD_CANCEL_DEFERRED
.


4. Les points d’annulation

Avec une annulation différée, le thread ne se termine pas immédiatement.

Il doit atteindre un point d’annulation.

Un point d’annulation est un emplacement où la bibliothèque vérifie si une demande d’annulation est en attente.

De nombreuses fonctions POSIX pouvant bloquer sont des points d’annulation.

Exemples courants :

Code: Select all

accept()
close()
connect()
fcntl()
open()
pause()
poll()
pread()
pselect()
pthread_cond_wait()
pthread_cond_timedwait()
read()
readv()
recv()
recvfrom()
recvmsg()
select()
send()
sendmsg()
sleep()
system()
tcdrain()
usleep()
wait()
waitpid()
write()
writev()
Cette liste dépend en partie de la norme et de l’implémentation.

Certaines fonctions peuvent être définies comme points d’annulation par une implémentation sans être obligatoirement présentes dans toutes les listes.

Les fonctions bloquantes sont particulièrement importantes, car elles empêchent qu’un thread reste bloqué indéfiniment alors qu’une demande d’annulation a été envoyée.


Comportement général

Lorsqu’un thread avec annulation activée et différée atteint un point d’annulation :
  • la demande en attente est détectée ;
  • les gestionnaires de nettoyage sont exécutés ;
  • les données spécifiques au thread sont nettoyées ;
  • le thread se termine ;
  • Code: Select all

    pthread_join()
    peut récupérer

    Code: Select all

    PTHREAD_CANCELED
    .

5. Créer explicitement un point d’annulation

Un thread peut exécuter une longue boucle sans appeler aucune fonction constituant un point d’annulation.

Dans ce cas, une demande différée pourrait ne jamais être traitée.

POSIX fournit :

Code: Select all

#include <pthread.h>

void pthread_testcancel(void);
Cette fonction ne renvoie aucune valeur.

Elle teste si une demande d’annulation est en attente.

Si aucune demande n’existe, elle retourne normalement.

Si une demande existe et que l’annulation est activée, le thread est annulé.

Exemple :

Code: Select all

void *fonction_thread(void *arg)
{
    for (;;) {
        effectuer_un_bloc_de_calcul();

        pthread_testcancel();
    }

    return NULL;
}
Cette fonction est utile dans :
  • les boucles de calcul ;
  • les traitements CPU longs ;
  • les algorithmes qui n’appellent pas de fonction bloquante ;
  • les threads qui doivent rester réactifs à une demande d’arrêt.

6. Récupérer le résultat d’un thread annulé

La fonction

Code: Select all

pthread_join()
permet d’attendre la fin d’un thread et de récupérer sa valeur de retour.

Lorsqu’un thread est annulé, la valeur récupérée vaut :

Code: Select all

PTHREAD_CANCELED
Exemple :

Code: Select all

void *resultat;

pthread_cancel(thread);

pthread_join(thread, &resultat);

if (resultat == PTHREAD_CANCELED) {
    printf("Le thread a été annulé\n");
} else {
    printf("Le thread s'est terminé normalement\n");
}
Il est important d’appeler

Code: Select all

pthread_join()
sur un thread joignable même après une annulation.

Cela permet de récupérer ses ressources système.


7. Exemple simple d’annulation différée

Code: Select all

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static void *fonction_thread(void *arg)
{
    (void)arg;

    puts("thread : démarré");

    for (;;) {
        puts("thread : boucle");

        sleep(1);
    }

    return NULL;
}

int main(void)
{
    pthread_t thread;
    void *resultat;
    int erreur;

    erreur = pthread_create(&thread, NULL, fonction_thread, NULL);
    if (erreur != 0) {
        fprintf(stderr, "pthread_create : %d\n", erreur);
        return EXIT_FAILURE;
    }

    sleep(3);

    erreur = pthread_cancel(thread);
    if (erreur != 0) {
        fprintf(stderr, "pthread_cancel : %d\n", erreur);
        return EXIT_FAILURE;
    }

    erreur = pthread_join(thread, &resultat);
    if (erreur != 0) {
        fprintf(stderr, "pthread_join : %d\n", erreur);
        return EXIT_FAILURE;
    }

    if (resultat == PTHREAD_CANCELED) {
        puts("main : thread annulé");
    } else {
        puts("main : fin normale");
    }

    return EXIT_SUCCESS;
}
Ici,

Code: Select all

sleep()
constitue un point d’annulation.

La demande envoyée par

Code: Select all

pthread_cancel()
est donc traitée lorsque le thread se trouve dans ou atteint cet appel.


8. Pourquoi l’annulation peut provoquer des fuites ou des deadlocks

Supposons qu’un thread effectue les opérations suivantes :

Code: Select all

pthread_mutex_lock(&mutex);

buffer = malloc(4096);

/* point d’annulation */

traiter(buffer);

free(buffer);
pthread_mutex_unlock(&mutex);
Si le thread est annulé au point d’annulation :
  • le bloc alloué peut ne jamais être libéré ;
  • le mutex peut rester verrouillé ;
  • les autres threads peuvent rester bloqués ;
  • l’état partagé peut rester incohérent.
Il faut donc enregistrer des fonctions de nettoyage avant d’entrer dans une zone où une annulation pourrait laisser des ressources actives.


9. Gestionnaires de nettoyage

POSIX fournit deux macros :

Code: Select all

pthread_cleanup_push()
pthread_cleanup_pop()
Leur usage général est :

Code: Select all

#include <pthread.h>

void pthread_cleanup_push(void (*routine)(void *), void *arg);
void pthread_cleanup_pop(int execute);
Elles permettent d’empiler et de retirer des gestionnaires de nettoyage associés au thread courant.


pthread_cleanup_push()

Ajoute un gestionnaire de nettoyage au sommet de la pile du thread.

La fonction de nettoyage doit avoir cette forme :

Code: Select all

void nettoyage(void *arg)
{
    /* Libération d’une ressource */
}

pthread_cleanup_pop()

Retire le gestionnaire placé au sommet de la pile.

Si

Code: Select all

execute
est non nul, le gestionnaire est exécuté immédiatement.

Si

Code: Select all

execute
vaut zéro, il est seulement retiré.


Ordre d’exécution

Les gestionnaires sont exécutés dans l’ordre inverse de leur enregistrement.

Il s’agit d’une pile LIFO :

Code: Select all

pthread_cleanup_push(nettoyage_1, arg1);
pthread_cleanup_push(nettoyage_2, arg2);
En cas d’annulation :

Code: Select all

nettoyage_2
nettoyage_1

10. Quand les gestionnaires sont-ils exécutés ?

Les gestionnaires de nettoyage sont exécutés automatiquement dans plusieurs situations importantes :
  • lorsqu’un thread est annulé ;
  • lorsque le thread appelle

    Code: Select all

    pthread_exit()
    ;
  • lorsque

    Code: Select all

    pthread_cleanup_pop(1)
    est utilisé.
Ils ne sont pas automatiquement exécutés lorsqu’un thread quitte simplement sa fonction avec

Code: Select all

return
, sauf si le programme les exécute explicitement avec

Code: Select all

pthread_cleanup_pop(1)
.

Il faut donc organiser le code pour que chaque appel à

Code: Select all

pthread_cleanup_push()
soit associé à un appel à

Code: Select all

pthread_cleanup_pop()
.


11. Attention : ce sont souvent des macros

Sur de nombreuses implémentations,

Code: Select all

pthread_cleanup_push()
et

Code: Select all

pthread_cleanup_pop()
sont des macros qui ouvrent et ferment un bloc lexical.

Elles doivent donc être utilisées dans la même portée.

Exemple correct :

Code: Select all

pthread_cleanup_push(nettoyage, ressource);

/* Travail */

pthread_cleanup_pop(1);
Exemple problématique :

Code: Select all

if (condition)
    pthread_cleanup_push(nettoyage, ressource);

/* Code */

pthread_cleanup_pop(1);
Il faut éviter les structures qui cassent l’appariement lexical.

Une forme plus sûre est :

Code: Select all

if (condition) {
    pthread_cleanup_push(nettoyage, ressource);

    /* Code */

    pthread_cleanup_pop(1);
}

12. Nettoyer une allocation mémoire

Code: Select all

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static void liberer_buffer(void *arg)
{
    free(arg);
    puts("buffer libéré");
}

static void *fonction_thread(void *arg)
{
    (void)arg;

    void *buffer = malloc(4096);
    if (buffer == NULL) {
        return NULL;
    }

    pthread_cleanup_push(liberer_buffer, buffer);

    for (;;) {
        sleep(1);
    }

    pthread_cleanup_pop(1);

    return NULL;
}
Si le thread est annulé pendant

Code: Select all

sleep()
, le gestionnaire appelle

Code: Select all

free()
.

Le buffer ne fuit donc pas.


13. Nettoyer un mutex

Code: Select all

#include <pthread.h>

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

static void deverrouiller_mutex(void *arg)
{
    pthread_mutex_t *m = arg;
    pthread_mutex_unlock(m);
}

static void *fonction_thread(void *arg)
{
    (void)arg;

    pthread_mutex_lock(&mutex);

    pthread_cleanup_push(deverrouiller_mutex, &mutex);

    /* Travail potentiellement annulable */

    pthread_cleanup_pop(1);

    return NULL;
}
Si le thread est annulé après le verrouillage, le gestionnaire déverrouille le mutex.

Cela évite un blocage permanent des autres threads.


14. Cas particulier de pthread_cond_wait()

La fonction :

Code: Select all

pthread_cond_wait()
est un point d’annulation.

Lorsqu’un thread est annulé pendant l’attente sur une variable de condition, POSIX garantit que le mutex associé est repris avant l’exécution des gestionnaires de nettoyage.

Cela permet à un gestionnaire de nettoyage d’appeler correctement :

Code: Select all

pthread_mutex_unlock()
Exemple :

Code: Select all

pthread_mutex_lock(&mutex);

pthread_cleanup_push(deverrouiller_mutex, &mutex);

while (!condition) {
    pthread_cond_wait(&cond, &mutex);
}

pthread_cleanup_pop(1);
Cette règle est essentielle.

Sans reprise préalable du mutex, le gestionnaire pourrait tenter de déverrouiller un mutex que le thread ne détient pas.


15. Exemple complet avec buffer, mutex et variable de condition

Code: Select all

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static int disponible = 0;

static void nettoyer_mutex(void *arg)
{
    pthread_mutex_t *m = arg;
    pthread_mutex_unlock(m);
    puts("nettoyage : mutex déverrouillé");
}

static void nettoyer_buffer(void *arg)
{
    free(arg);
    puts("nettoyage : buffer libéré");
}

static void *fonction_thread(void *arg)
{
    (void)arg;

    void *buffer = malloc(4096);
    if (buffer == NULL) {
        return NULL;
    }

    pthread_cleanup_push(nettoyer_buffer, buffer);

    pthread_mutex_lock(&mutex);
    pthread_cleanup_push(nettoyer_mutex, &mutex);

    while (!disponible) {
        pthread_cond_wait(&cond, &mutex);
    }

    pthread_cleanup_pop(1);
    pthread_cleanup_pop(1);

    return NULL;
}

int main(void)
{
    pthread_t thread;
    void *resultat;

    if (pthread_create(&thread, NULL, fonction_thread, NULL) != 0) {
        return EXIT_FAILURE;
    }

    sleep(1);

    pthread_cancel(thread);
    pthread_join(thread, &resultat);

    if (resultat == PTHREAD_CANCELED) {
        puts("thread annulé proprement");
    }

    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mutex);

    return EXIT_SUCCESS;
}
Ordre du nettoyage en cas d’annulation :

Code: Select all

1. le mutex est repris par pthread_cond_wait()
2. nettoyer_mutex() est exécuté
3. nettoyer_buffer() est exécuté
4. le thread se termine

16. Désactiver l’annulation dans une section critique

Un gestionnaire de nettoyage n’est pas toujours suffisant.

Certaines opérations doivent être terminées entièrement avant qu’une annulation puisse être acceptée.

Exemple :

Code: Select all

int ancien_etat;

pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &ancien_etat);

mettre_a_jour_structure();
ecrire_etat_sur_disque();
valider_transaction();

pthread_setcancelstate(ancien_etat, NULL);
Si une demande a été envoyée pendant la section non annulable, elle reste en attente.

Lorsque l’ancien état est restauré, la demande peut être traitée au prochain point d’annulation.


17. Annulation asynchrone

Le mode asynchrone est activé avec :

Code: Select all

pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
Dans ce mode, le thread peut être interrompu presque partout.

Cela rend très difficile la garantie d’un état cohérent.

Exemple dangereux :

Code: Select all

pthread_mutex_lock(&mutex);

compteur++;
liste = modifier_liste(liste);

pthread_mutex_unlock(&mutex);
Le thread peut être annulé après

Code: Select all

pthread_mutex_lock()
mais avant

Code: Select all

pthread_mutex_unlock()
.

Il peut aussi être annulé pendant une fonction de la bibliothèque comme

Code: Select all

malloc()
.

La bibliothèque elle-même peut alors rester dans un état interne indéterminé.


Règle pratique

N’utiliser l’annulation asynchrone que pour du code extrêmement limité qui :
  • n’alloue pas de mémoire ;
  • ne détient aucun verrou ;
  • ne modifie aucune structure partagée ;
  • n’appelle presque aucune fonction de bibliothèque ;
  • ne dépend d’aucun invariant complexe.
Dans la majorité des programmes, il vaut mieux ne jamais l’utiliser.


18. Héritage des paramètres d’annulation

Un nouveau thread démarre généralement avec :

Code: Select all

PTHREAD_CANCEL_ENABLE
PTHREAD_CANCEL_DEFERRED
Il ne faut pas supposer qu’un nouveau thread hérite automatiquement de tous les paramètres temporaires d’annulation du thread créateur.

Chaque thread doit configurer explicitement son propre comportement lorsqu’un autre choix est nécessaire.


19. Annulation et fork()

Après un appel à

Code: Select all

fork()
dans un programme multithread, seul le thread appelant existe dans le processus enfant.

L’état d’annulation du thread appelant est conservé dans l’enfant.

Le programme doit néanmoins rester très prudent, car les verrous détenus par d’autres threads au moment du

Code: Select all

fork()
peuvent rester dans un état problématique dans le processus enfant.


20. Erreurs de conception courantes

1. Croire que pthread_cancel() tue immédiatement le thread

Il s’agit uniquement d’une demande.

Avec le mode différé, le thread doit atteindre un point d’annulation.


2. Oublier pthread_join()

Un thread annulé doit toujours être rejoint s’il est joignable.


3. Annuler un thread qui détient un mutex

Sans gestionnaire de nettoyage, le mutex peut rester verrouillé.


4. Ne pas protéger les allocations

Un thread annulé peut abandonner des blocs mémoire ou des descripteurs ouverts.


5. Utiliser PTHREAD_CANCEL_ASYNCHRONOUS sans nécessité

Cela rend le code presque impossible à raisonner correctement.


6. Ne jamais appeler de point d’annulation

Une boucle CPU sans appel bloquant doit invoquer

Code: Select all

pthread_testcancel()
périodiquement.


7. Mal apparier cleanup_push et cleanup_pop

Les deux macros doivent rester dans le même bloc lexical.


8. Utiliser return en pensant déclencher les gestionnaires

Un retour normal de la fonction du thread ne garantit pas l’exécution automatique des gestionnaires encore empilés.


21. Alternative recommandée : arrêt coopératif explicite

Dans de nombreux programmes, un drapeau d’arrêt explicite est plus simple et plus sûr que

Code: Select all

pthread_cancel()
.

Exemple avec variable atomique :

Code: Select all

#include <pthread.h>
#include <stdatomic.h>
#include <stdio.h>
#include <unistd.h>

static atomic_bool arret = false;

static void *fonction_thread(void *arg)
{
    (void)arg;

    while (!atomic_load(&arret)) {
        effectuer_travail();
    }

    return NULL;
}

int main(void)
{
    pthread_t thread;

    pthread_create(&thread, NULL, fonction_thread, NULL);

    sleep(3);

    atomic_store(&arret, true);

    pthread_join(thread, NULL);

    return 0;
}
Avantages :
  • flux de contrôle plus explicite ;
  • nettoyage plus facile à comprendre ;
  • pas d’interruption cachée dans une fonction ;
  • meilleure portabilité logique ;
  • moins de risques de deadlock.
Cependant,

Code: Select all

pthread_cancel()
reste utile lorsqu’un thread est bloqué dans une fonction POSIX constituant un point d’annulation.


22. Modèle professionnel recommandé

Un modèle robuste consiste à :
  • utiliser l’annulation différée ;
  • installer les gestionnaires de nettoyage avant d’acquérir des ressources annulables ;
  • limiter la durée des sections où l’annulation est désactivée ;
  • insérer

    Code: Select all

    pthread_testcancel()
    dans les longues boucles ;
  • rejoindre systématiquement les threads ;
  • privilégier un arrêt coopératif lorsque cela suffit.
Exemple de squelette :

Code: Select all

static void *fonction_thread(void *arg)
{
    int ancien_etat;

    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &ancien_etat);

    initialiser_ressources();

    pthread_cleanup_push(nettoyer_ressources, arg);

    pthread_setcancelstate(ancien_etat, NULL);

    for (;;) {
        effectuer_travail();

        pthread_testcancel();
    }

    pthread_cleanup_pop(1);

    return NULL;
}
L’idée consiste à empêcher l’annulation pendant l’initialisation, puis à l’activer seulement après l’installation du gestionnaire de nettoyage.


23. API récapitulatives

pthread_cancel()

Code: Select all

int pthread_cancel(pthread_t thread);
Envoie une demande d’annulation.


pthread_setcancelstate()

Code: Select all

int pthread_setcancelstate(int state, int *oldstate);
Active ou désactive la prise en compte des demandes d’annulation.


pthread_setcanceltype()

Code: Select all

int pthread_setcanceltype(int type, int *oldtype);
Choisit entre annulation différée et asynchrone.


pthread_testcancel()

Code: Select all

void pthread_testcancel(void);
Crée explicitement un point d’annulation.


pthread_cleanup_push()

Code: Select all

void pthread_cleanup_push(void (*routine)(void *), void *arg);
Empile un gestionnaire de nettoyage.


pthread_cleanup_pop()

Code: Select all

void pthread_cleanup_pop(int execute);
Retire le dernier gestionnaire et l’exécute éventuellement.


pthread_join()

Code: Select all

int pthread_join(pthread_t thread, void **retval);
Attend la fin du thread et permet de vérifier si le résultat vaut

Code: Select all

PTHREAD_CANCELED
.


24. Valeurs et constantes importantes

Code: Select all

PTHREAD_CANCEL_ENABLE
PTHREAD_CANCEL_DISABLE

PTHREAD_CANCEL_DEFERRED
PTHREAD_CANCEL_ASYNCHRONOUS

PTHREAD_CANCELED
Signification :
  • Code: Select all

    PTHREAD_CANCEL_ENABLE
    : annulation activée ;
  • Code: Select all

    PTHREAD_CANCEL_DISABLE
    : annulation désactivée ;
  • Code: Select all

    PTHREAD_CANCEL_DEFERRED
    : annulation aux points d’annulation ;
  • Code: Select all

    PTHREAD_CANCEL_ASYNCHRONOUS
    : annulation possible presque partout ;
  • Code: Select all

    PTHREAD_CANCELED
    : valeur récupérée par

    Code: Select all

    pthread_join()
    après annulation.

25. Résumé final

L’annulation POSIX est un mécanisme de terminaison coopérative.

Code: Select all

pthread_cancel()
envoie une demande, mais le thread décide indirectement du moment où elle sera appliquée grâce à son état et à son type d’annulation.

Le mode normal est :

Code: Select all

PTHREAD_CANCEL_ENABLE
PTHREAD_CANCEL_DEFERRED
Dans ce mode, l’annulation se produit à un point d’annulation.

Code: Select all

pthread_testcancel()
permet d’en créer un explicitement.

Les gestionnaires :

Code: Select all

pthread_cleanup_push()
pthread_cleanup_pop()
sont essentiels pour libérer la mémoire, fermer les fichiers et déverrouiller les mutex.

L’annulation asynchrone est extrêmement risquée et doit presque toujours être évitée.

Dans un programme moderne et robuste, il faut préférer :
  • l’annulation différée ;
  • le nettoyage structuré ;
  • l’arrêt coopératif explicite ;
  • l’attente finale avec

    Code: Select all

    pthread_join()
    .

Who is online

Users browsing this forum: No registered users and 0 guests