Dans la plus part des SE , chaque processus possède un espace d'adressage et un
threads de contrôle unique : c'est le thread principale. c'est se dernier qui
exécute le main. le mot threads se threads se traduit par file d'exécution . toute
les fonction relative au threads sont dans le fichier <pthread.h> dans le
biblitheque <lbpthread.a>
MANIPULATION DES THREADS
Créer un thread
Pour créer un thread, il faut déclarer une var de représentant. celle si sera de
type p_thread, qui est un typedef d'unsigned long int et fonction pthread-create.
#include <pthread.h>
int pthread-create (pthread_t * thread ,pthread-attr_t * attr, void * (*start-
routine) (void*) , void * arg);
ce prototype semble compliquer mais simple d'utilisation :
-la fonction renvoie une valeur de type int :
0 si la creation est reussi et une autre valeur si ya erreur .
- le premier argument est un pointeur vers l'id du thread.
-le second argument designe les attribut du thread , on peut choisir de mettre le
thread en etat joignable (par defaut) ou detacher , et choisir sa politique d'
ordonnancement (usuelle , temps reel ); nous mettrons généralement null
- la troisiement est un pointeur vers la fonction a exécuter et contient le code a
executer par le thread.
-enfin le dernier argument est l'argment a passer au thread .
Supprimer un thread
comme dans la vie , supprimer est plus facile que créer et on utilise la fonction
pthread-exit
#include <pthread.h>
void pthread-exit (void*ret);
application
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
void * thead_ (void * arg )
{
printf ('nous avons somme dans le thread .\n");
(void)arg;
pthread-exit(NULL);
}
int main (void) {
pthread_t thread
printf ("Avant la creation dun thread thread. \n");
if (pthread-create ( pthreadA, null , thread_1 , null) ==-1)
{ perror("pthread-crete");
return EXIT_FAILLURE;
{ perror("Apres la creation du thread.\");
return EXIT_SUCCESS;
}
Dans la pratique , avec les processus, le thread principale n'attendra de lui meme
que le thread se termine avant d'excuter son code par consequent , il va falloir
le faire attendre et dieu pthread crea : pthread-join
#include <pthread.h>
int pthread-join ( pthread_t th , void*thread_return);
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
void * thread_1(void*arg){
printf("nous avons somme dans le thread .\n");
(void) * arg;
pthread_exit (NULL)
}
int main (void) {
{
pthread_t thread1 ;
printf ("Avant la creation dun thread thread. \n");
if (pthread-create ( pthread1, null , thread_1 , null) ==-1)
{
perror("pthread-create");
return EXIT_FAILLURE;
if (pthread-jon ( pthread1, null ) ==-1)
perror("pthread-join");
return EXIT_FAILLURE;
}
printf ("Apres la creation dun thread thread. \n");
return EXIT_SUCCESS;
}
Les exclusions mutuelles
dans la gestion des thread , les variable sont gérer dans la mémoire
partager , ce qui cause problème c'est quand un thread lit une variable pendant
qu'un autre tente de la modifier, oïl est donc nécessaire d adapter un mécanisme de
synchronisation appeler : exclusions mutuelles (ex mutex)
concrètement un mutex est une variable de type : pthread-mutex-t , qui sert
de verrou. ce verrou a deux état : disponible et verrouiller . Le mutex se déclare
dans une structure avec la donner a partager .
typedef struct data {
int var ;
pthread-mutex-t mutex;
} data;
on manipule les mutex grace a pthread
Initialiser un mutex
on initialise un mutex avec la valeur de la constante PTHREAD_MUTEX-INITIALIZER
declarer dans pthread.h
#include <stdlib.h>
#include <pthread.h>
typedef struct data {
int var ;
pthread-mutex-t mutex;
} data;
int main (void)
{
data new-data;
new-data.mutex= THREAD_MUTEX-INITIALIZER ;
return EXIT_SUCCESS;
}
Verrouiller un mutex
#include <stdlib.h>
#include <pthread.h>
int pthread-mutex_lock (pthread-mutex_t *mut );
déverrouiller un mutex
#include <pthread.h>
int pthread-mutex_unlock (pthread-mutex-t *mut );
detruire un mutex
#include <pthread.h>
int pthread-mutex_destroy (pthread-mutex-t *mut );
Condition
lorsqu'un doit patienter jusqu'à ce qu'un évènement le survienne dans un autre
thread , on parle de condition .
Quand un thread d'un condition , il reste bloquer tant que celle-ci n'est pas
réaliser par un autre thread .
on declare la condition en variable global
pthread_condition nomcondition = PTHREAD_CONDITION-INITIALIZER ;
pour attendre une conditions :
int pthread_condition_wait (pthread_cond_t*nomcondition , pthread_mutex_t
*nomMutex);
pour reveiller un thread en attente d'une condition
int pthread_condition_signal ( pthread_cond_t * nomCondition );
application
ecrire un code qui crée deux threads : un qui incrémente ue variale compteur par un
nombre tiré au hasard entre 0 a 10 , et l'autre qui affiche un message lorsque la
variable compteur depasse 20.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
pthread_cond_t condition = PTHREAD_CONDITION-INITIALIZER ;
pthread_mutex_t mutex = PTHREAD_MUTEX-INITIALIZER ;
void* threadAlarme (void*arg);
void* threadCompteur (void*arg);
int main (void)
{
pthrea_t monthreadcompteur ;
pthrea_t monthreadAlarme ;
pthread-create (pthreadcompteur , null, threadcompeur, (*void)null );
pthread-create (pthreadalarme , null, threadalarme, (*void) null );
thread_join(monthreadcompteur, null);
thread_join(monthreadalarme, null);
return 0 ;
}
void* threadcompteur (void*arg)
{
int compteur = 0, nombre = 0;
srand (time(null));
while (1)
{
nombre = rand()%10 ;
if ( compteur += nombre ) :
printf("\n %d, compteur ):
if (compteur >= 20 )
{
pthread-mutex_lock (p_mutex);
pthread_cond_signal (p_condition);
compteur = vide (0/) ;
} sleep(1)
pthread-exit(null);
}
void threadalarne (void*arg)
{while (1){
pthread-mutex_lock(pmutex);
pthread_cond_wait(pcondition,pmutex)
printf("\LE COMPTEUR A DEPASSER 20 ") ;
pthread_mutex_unlock(pmutex);
}
pthread_exit(NULL)
}
LES TUBES
un tubes peut entre présenter comme un tableau dans lequel se trouves les
information . les tubes servent a communiquer plusieurs processus entre eux . on
distingue alors les processus par leur actions :
-un qui écris dans le tubes , c'est la clé du tubes
-l'autre qui lit dans le tubes appeler sorti du tubes
pour créer un tubes on utilise a fonction
int pipe (int descripteur [2] ):
- elle renvoie une valeur de type int qui est de 0 si elle réussit ou une autre
valeur dans le cas contraire
-elle prend en argument un tableau de int comprenant ;
* descripteur de 0 qui désigne la sorti du tube
*descripteur de 1 qui désigne l'entrer du tube
on crée le tube dans un seul processus , l'autre ne peut donc en connaitre l'entrer
ou la sorti d'où la nécessiter de créer en utilisant pipe avant fork
le père et le fils auront les même valeur dans le tableau descripteur et pourront
communiquer .
Ecrire :
pour écrire dans un tubes
ssize_t write (int entreetube, const void* elementaecrire , size_t
nombreoctetaecire);
la fonction prend en paramètre l entrer du tubes , un compteur generique vers la
mémoire contenant l'element a ecrire ainsi que le nombre d'octer de cet element.
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/wait.h>
#define TAILLE_MESSAGE 256
Int main (void)
{
pid_t pidfils;
int descriptiontube[2];
char messageecrire[TAILLE_MESSAGE];
pipe (descriptiontube)
pidfils=fork()
if (pidfils==0)
{
sprintf(messageecrire,"bonjour, fils, c'est le père ");
write (descripteurTUBE[1],messageecrire, TAILLE_MESSAGE)
}
return EXIT_SUCCESS;
}
lire :
pour lire dans un tube :
ssize_t read (int sortietube, void * elementalire, size_t nombreoctetalire);
la fonction prend en paramètre la sortie du pointeur vers la mémoire contenant
l,'élément a lire et le nombre octet de l élément .
elle renvoie une valeur de ssize_t qui correspond au nombre d'octet effectivement
lu , on pourra comparer le troisième paramètre (nombreoctetlire) a la valeur
renvoyer pour être sur qu'il y a pas d'erreur .
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/wait.h>
#define TAILLE_MESSAGE 256
Int main (void)
{
pid_t pidfils;
int descriptiontube[2];
char messageelire[TAILLE_MESSAGE];
pipe (descriptiontube)
pidfils=fork()
if (pidfils==0)
{
read(descriptiontube[0],messagelire,TAILLE_MESSAGE);
printf("message recu=\"%S\"",messagelire);
}
return EXIT_SUCCESS;
}
Fermer
pour fermer une entrer ou une sorti on utilse la fonction close
int close 9int descripteur);
la valeur en paramètre correspond a la valeur soit de l entrer ou de la sortie a
fermer
exemple de code pour fermer l'entrer du processus et la sorti du processus père
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/wait.h>
#define TAILLE_MESSAGE 256
Int main (void)
{
pid_t pidfils;
int descriptiontube[2];
pipe (descriptiontube);
pidfils=fork()
if (pidfils=/0)
{
close (descriptiontube[1]);
}else{
close (descriptiontube[0]);
}
return EXIT_SUCCESS;
}
pratique
ecrire un programme qui cree 2 processus le père qui ecris "bonjour fils je suis le
père " et le fils qui recu le message pour l aficher .
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/wait.h>
#define TAILLE_MESSAGE 256
Int main (void)
{
pid_t pidfils;
int descriptiontube[2];
unsigned char messagealire[TAILLE_MESSAGE],mesageaecrire[TAILLE_MESSAGE]
printf("message de tube.\n");
if (pipe (descriptiontube)!=0/)
{
fprint (stder,"ecrire de creation du tube .\n");
return EXIT_FAILLURE
}
pidfils=fork()
if (pidfils==-1)
{
fprint (stder,"ERREUR de creation du tube .\n");
return 1;
}if (pidfils==0/)
{
fprint ("Ffermetture de l'entrer dans le fils .\n\n");
close (descriptiontube[1]) ;
read(descriptiontube[0],messagelire,TAILLE_MESSAGE);
fprint ("nous sommes dans le fils pid=%d).\n"
le message recu du pere est .\%s \".\n\n\n", GETPID(), messaglire );
} else {
fprint ("Ffermetture de la sortie dans le fils .\n\n");
close (descriptiontube[0]) ;
sprint(messageecrire,"bonjour , le fils je suis le pere .");
print("nous sommes dans le pere(pid=%d)\n il envoie le message suivante au
fils : .\%s \".\n\n\n", GETPID() , messageecrire);
write (description[1], messageecrire;
TAILLE_MESSAGE)
WAIT (NULL);
}
return 0/;
}