Développement de programmes à unités d'exécution multiples

Le développement de programmes à unités d'exécution multiples est similaire au développement de programmes à processus multiples. Le développement de programmes consiste également à compiler et à déboguer le code.

Compilation d'un programme à unités d'exécution multiples

Cette section explique comment générer un programme à unités d'exécution multiples. Il décrit ce qui suit:
  • Fichier d'en-tête requis
  • Appel du compilateur, qui est utilisé pour générer des programmes à unités d'exécution multiples.

Fichier d'en-tête

Tous les prototypes de sous-programmes, macros et autres définitions permettant d'utiliser la bibliothèque d'unités d'exécution se trouvent dans le fichier d'en-tête pthread.h , qui se trouve dans le répertoire /usr/include . Le fichier d'en-tête pthread.h doit être inclus dans chaque fichier source à l'aide de la bibliothèque d'unités d'exécution.

L'en-tête pthread.h inclut l'en-tête unistd.h , qui fournit les définitions globales suivantes:

_POSIX_REENTRANT_FONCTIONS
Indique que toutes les fonctions doivent être réentrantes. Plusieurs fichiers d'en-tête utilisent ce symbole pour définir des sous-routines réentrantes supplémentaires, telles que la sous-routine localtime_r .
_POSIX_THREADS
Indique l'API d'unités d'exécution POSIX . Ce symbole permet de vérifier si l'API d'unités d'exécution POSIX est disponible. Les macros ou les sous-routines peuvent être définies de différentes manières, selon que l'API POSIX ou d'autres unités d'exécution sont utilisées.

Le fichier pthread.h inclut également errno.h, dans lequel la variable globale errno est redéfinie pour être spécifique à l'unité d'exécution. L'identificateur errno n'est donc plus une valeur l-value dans un programme à unités d'exécution multiples.

Appel du compilateur

Lors de la compilation d'un programme à unités d'exécution multiples, appelez le compilateur C à l'aide de l'une des commandes suivantes:
xlc_r
Appelle le compilateur avec le niveau de langage par défaut ansi
cc_r
Appelle le compilateur avec le niveau de langage par défaut étendu

Ces commandes garantissent que les options et les bibliothèques adéquates sont utilisées pour être conformes à la spécification UNIX unique, version 2. La spécification POSIX Threads Specification 1003.1c est un sous-ensemble de la spécification Single UNIX Specification, Version 2.

Les bibliothèques suivantes sont automatiquement liées à votre programme lors de l'utilisation des commandes xlc_r et cc_r :
libpthreads.a
Bibliothèque d'unités d'exécution
libc.a
Bibliothèque C standard
Par exemple, la commande suivante compile le fichier source C à unités d'exécution multiples foo.c et génère le fichier exécutable foo :
cc_r -o foo foo.c

Appel du compilateur pour le brouillon 7 de POSIX 1003.1c

AIX assure la compatibilité du code source pour les applications Draft 7. Il est recommandé aux développeurs de porter leur application à unités d'exécution vers la norme la plus récente.

Lors de la compilation d'un programme à unités d'exécution multiples pour la prise en charge des unités d'exécution Draft 7, appelez le compilateur C à l'aide de l'une des commandes suivantes:
xlc_r7
Appelle le compilateur avec le niveau de langage par défaut ansi
cc_r7
Appelle le compilateur avec le niveau de langage par défaut étendu
Les bibliothèques suivantes sont automatiquement liées à votre programme lors de l'utilisation des commandes xlc_r7 et cc_r7 :
libpthreads_compat.a
Bibliothèque d'unités d'exécution de compatibilité Draft 7
libpthreads.a
Bibliothèque d'unités d'exécution
libc.a
Bibliothèque C standard

Pour assurer la compatibilité du code source, utilisez la directive de compilation _AIX_PTHREADS_D7. Il est également nécessaire de lier les bibliothèques dans l'ordre suivant: libpthreads_compat.a, libpthreads.aet libc.a. La plupart des utilisateurs n'ont pas besoin de connaître ces informations, car les commandes fournissent les options nécessaires. Ces options sont fournies pour ceux qui ne disposent pas du dernier compilateur AIX .

Portage des applications brouillon 7 vers &Symbol.unixspec;

Il existe des différences entre l'ébauche 7 et la norme finale:
  • Différences errno mineures. La plus courante est l'utilisation de ESRCH pour indiquer que le pthread spécifié est introuvable. Le brouillon 7 a fréquemment renvoyé EINVAL pour cet échec.
  • L'état par défaut lors de la création d'une unité d'exécution de type pthread est joinable. Il s'agit d'une modification importante car elle peut entraîner une fuite de mémoire si elle est ignorée.
  • Le paramètre de planification pthread par défaut est scope.
  • La sous-routine pthread_yield a été remplacée par la sous-routine sched_yield .
  • Les différentes règles de planification associées aux verrous de processus mutex sont légèrement différentes.

Configuration mémoire requise pour un programme à unités d'exécution multiples

AIX prend en charge jusqu'à 32768 unités d'exécution dans un seul processus. Chaque pthread requiert une certaine quantité d'espace adresse de processus, de sorte que le nombre maximal réel de pthreads qu'un processus peut avoir dépend du modèle de mémoire et de l'utilisation de l'espace adresse de processus, à d'autres fins. La quantité de mémoire dont un pthread a besoin inclut la taille de la pile et la taille de la région de garde, plus une certaine quantité pour une utilisation interne. L'utilisateur peut contrôler la taille de la pile avec la sous-routine pthread_attr_setstacksize et la taille de la région de garde avec la sous-routine pthread_attr_setguardsize .
Remarque: La limite souple de la taille de pile imposée par la commande ulimit -s s'applique uniquement à la pile de l'unité d'exécution principale de l'application.
Le tableau suivant indique le nombre maximal de pthreads pouvant être créés dans un processus 32 bits à l'aide d'un programme simple qui ne fait rien d'autre que créer des pthreads dans une boucle à l'aide de l'attribut pthread NULL. Dans un programme réel, les nombres réels dépendent d'une autre utilisation de la mémoire dans le programme. Pour un processus 64 bits, la sous-routine ulimit contrôle le nombre d'unités d'exécution pouvant être créées. Par conséquent, le modèle big data n'est pas nécessaire et peut en fait réduire le nombre maximal d'unités d'exécution.
Modèle de données -bmaxdata Nombre maximal d'unités d'exécution
Données de petite taille non disponible 1084
Volumes massifs de données 0x10000000 2169
Volumes massifs de données 0x20000000 4340
Volumes massifs de données 0x30000000 6510
Volumes massifs de données 0x40000000 8681
Volumes massifs de données 0x50000000 10852
Volumes massifs de données 0x60000000 13022
Volumes massifs de données 0x70000000 15193
Volumes massifs de données 0x80000000 17364
La variable d'environnement NUM_SPAREVP peut être définie pour contrôler le nombre de processeurs virtuels de secours gérés par la bibliothèque. Il n'est pas nécessaire de modifier cette variable. Dans certains cas, les applications qui n'utilisent que quelques mégaoctets de mémoire peuvent réduire le temps système de la mémoire en définissant la variable d'environnement NUM_SPAREVP sur une valeur inférieure. Les paramètres standard incluent le nombre d'unités centrales sur le système ou le nombre maximal d'unités d'exécution de processus. La définition de cette variable n'affecte pas les performances du processus. La valeur par défaut est 256.
Remarque: la variable d'environnement NUM_SPAREVP est disponible uniquement dans AIX 5.1.

Exemple de programme à unités d'exécution multiples

Le programme à unités d'exécution courtes suivant affiche "Hello !" en français et en anglais pendant cinq secondes. Compilez avec cc_r ou xlc_r. F
#include <pthread.h>    /* include file for pthreads - the 1st */
#include <stdio.h>      /* include file for printf()           */
#include <unistd.h>     /* include file for sleep()            */

void *Thread(void *string)
{
        while (1)
                printf("%s\n", (char *)string);
        pthread_exit(NULL);
}

int main()
{
        char *e_str = "Hello!";
        char *f_str = "Bonjour !";

        pthread_t e_th;
        pthread_t f_th;

        int rc;

        rc = pthread_create(&e_th, NULL, Thread, (void *)e_str);
        if (rc)
                exit(-1);
        rc = pthread_create(&f_th, NULL, Thread, (void *)f_str);
        if (rc)
                exit(-1);
        sleep(5);

        /* usually the exit subroutine should not be used
           see below to get more information */
        exit(0);
}

L'unité d'exécution initiale (exécutant la routine main ) crée deux unités d'exécution. Les deux unités d'exécution ont la même routine de point d'entrée (la routine Thread ), mais un paramètre différent. Le paramètre est un pointeur vers la chaîne qui sera affichée.

Débogage d'un programme à unités d'exécution multiples

Les outils suivants sont disponibles pour déboguer les programmes à unités d'exécution multiples:
  • Les programmeurs d'application peuvent utiliser la commande dbx pour effectuer le débogage. Plusieurs sous-commandes sont disponibles pour l'affichage des objets liés aux unités d'exécution, notamment attribute, condition, mutexet thread.
  • Les programmeurs du noyau peuvent utiliser le programme de débogage du noyau pour effectuer le débogage sur les extensions du noyau et les pilotes de périphériques. Le programme de débogage du noyau fournit un accès limité aux unités d'exécution utilisateur et gère principalement les unités d'exécution du noyau. Plusieurs sous-commandes prennent en charge plusieurs unités d'exécution et processeurs du noyau, notamment:
    • La sous-commande cpu , qui modifie le processeur en cours
    • La sous-commande ppd , qui affiche les structures de données par processeur
    • La sous-commande thread , qui affiche les entrées de la table d'unités d'exécution
    • La sous-commande uthread , qui affiche la structure uthread d'une unité d'exécution
    Pour plus d'informations sur le programme de débogage du noyau, voir Kernel Extensions and Device Support Programming Concepts.

Exigences relatives aux fichiers principaux d'un programme à unités d'exécution multiples

Par défaut, les processus ne génèrent pas de fichier core complet. Si une application doit déboguer des données dans des régions de mémoire partagée, en particulier des piles d'unités d'exécution, il est nécessaire de générer un cliché du processus core complet. Pour générer des informations complètes sur les fichiers core, exécutez la commande suivante en tant que superutilisateur:
	chdev -l sys0 -a fullcore=true

Chaque pthread individuel s'ajoute à la taille du fichier core généré. La quantité d'espace de fichier principal dont un pthread a besoin inclut la taille de pile, que l'utilisateur peut contrôler avec la sous-routine pthread_attr_setstacksize . Pour les pthreads créés avec l'attribut pthread NULL, chaque pthread dans un processus 32 bits ajoute 128 Ko à la taille du fichier core, et chaque pthread dans un processus 64 bits ajoute 256 Ko à la taille du fichier core.