/**************** EXERCICE *************************************************************
Créer quatre threads auxquelles la thread mère envoie un cancel. 
Chacune des threads fait une boucle d'inscrémentation d'un premier compteur puis
d'un deuxième compteur dédiés et a un comportement particulier vis-à-vis des cancels :
. la première masque les cancels pendant toute son exécution ;
. la seconde reçoit les cancels n'importe quand ;
. la troisième n'accepte un cancel qu'à la fin de la première boucle de façon asynchrone;
. et la quatrième masque les cancels pendant sa première boucle et les autorise pendant la seconde.
*/
/* cancel.c */
/* Envoi de cancels */
/* A compiler avec l'option -threads ou -lpthread selon les systèmes */
/* Il faut que le comptage dans les threads dure assez longtemps pour que la thread mere puisse envoyer un cancel a une thread pendant que celle-ci s'execute encore */

#include <pthread.h>

#define NbTh 4
int compteur[NbTh]={0,0,0,0};	pthread_t tid[NbTh];

void * fille1(void *); 	void * fille2(void *);
void * fille3(void *);	void * fille4(void *);
void * Filles[]={fille1, fille2, fille3, fille4};

/* *************   fonction executee par  fille1 */
void *fille1 (void *k){
/* masquage des cancels pendant toute l'execution */
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
while (compteur[0]<20000000) compteur[0]++;
}

/* *************   fonction executee par  fille2 */
void *fille2 (void *k) {   /* aucun masquage => recoit les cancels uniquement quand elle le desire */
while( compteur[1] < 100000000 )
compteur[1]++;	/* 1ere boucle */
pthread_testcancel();
/* 2eme boucle  : s'il y a eu un cancel, cette boucle ne sera pas du tout executee */
while( compteur[1] < 200000000 )
compteur[1]++;
}

/* *************   fonction executee par fille3 */
void *fille3 (void *k) {
/* recoit les cancels de facon asynchrone: n'importe quand */
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
while( compteur[2] < 900000000 ) compteur[2]++;
}

/* *************   fonction executee par fille4 */
void *fille4 (void *k) {
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);  	/* masquage des cancels */
while( compteur[3] < 100000000 )
compteur[3]++;	/* 1ere boucle */
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);  		/* demasquage des cancels */
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
/* 2eme boucle  : s'il y a un cancel, cette boucle sera interrompue */
while( compteur[3] < 200000000 )
compteur[3]++;
}

main() {
int i,  num;
/* creation des threads */
for(num=0;num<NbTh;num++) 	
      pthread_create(tid+num, 0, (void *(*)())Filles[num], (void *) num);
/* envoi d'un cancel a toutes les threads */
for(i=0;i<NbTh;i++)  pthread_cancel(tid[i]); 
/* attente de la terminaison de toutes les threads */
for(i=0;i<NbTh;i++)  pthread_join(tid[i], NULL); 
printf("Affichage des compteurs\n");
printf("%d \t%d \t%d \t%d\n", compteur[0], compteur[1], compteur[2], compteur[3]);
exit(0); 
}
