4. Créer un thread POSIX
POSIX expose ses types et routines de threads dans pthread.h; Windows possède une API distincte. Les objets POSIX sont manipulés par leurs fonctions plutôt que par leur représentation interne, qui doit être considérée comme opaque.
4.1 Contrat de pthread_create
L’interface centrale est :
Code (c) · sélectionner pour copier
int pthread_create(
pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg
);
| Paramètre | Rôle |
|---|---|
thread |
Adresse où sera écrit l’identifiant du nouveau thread. |
attr |
Attributs de création; NULL demande les valeurs par défaut. |
start_routine |
Fonction exécutée par le nouveau thread. |
arg |
Pointeur générique transmis à cette fonction. |
La fonction retourne 0 en cas de succès et un code d’erreur autrement. Un programme robuste vérifie cette valeur avant d’utiliser l’identifiant reçu.
La routine de départ a une signature compatible avec :
Code (c) · sélectionner pour copier
void *travail(void *argument);
Le pointeur générique permet de transmettre une structure contenant plusieurs paramètres. L’instance pointée doit rester valide aussi longtemps que le thread peut la lire.
4.2 Arguments stables
Une erreur classique consiste à passer à tous les threads l’adresse de la même variable de boucle. Le créateur la modifie pendant que les travailleurs tentent de la lire; plusieurs peuvent alors observer la dernière valeur ou une valeur inattendue.
Une stratégie correcte consiste à préparer un tableau d’arguments ou une structure distincte par travailleur :
Code (c) · sélectionner pour copier
struct Parametre {
int numero;
/* autres données */
};
Le tableau et ses éléments doivent survivre jusqu’à la fin des lectures. Une allocation locale disparue, une adresse réutilisée ou un objet détruit trop tôt produit un pointeur pendant.
4.3 Attributs et terminaison
Des objets pthread_attr_t peuvent préciser notamment la taille de pile ou certains paramètres d’ordonnancement. Ils sont initialisés avec pthread_attr_init et libérés avec pthread_attr_destroy. Les valeurs par défaut suffisent souvent aux exercices; un changement de taille ou de politique doit répondre à une nécessité explicite.
La routine peut terminer en retournant un void * ou par pthread_exit. La fin d’un travailleur ne termine pas automatiquement les autres threads. En revanche, si le processus entier se termine, ses threads disparaissent avec lui.
Dans un environnement coopératif, une opération de rendement volontaire (yield) permet à un thread de céder l’exécution. Le nom exact et le statut de cette opération varient selon l’environnement; elle ne remplace ni une attente de terminaison ni une protection de données.