=================================================
INFO 1 - Systèmes d’Exploitations - TP4 - Threads
=================================================


Avant-propos
------------

Un processus Unix est une structure d’information noyau (descripteurs des
fichiers ouverts, implantation mémoire, pile, signaux…).
Contrairement à `fork()` qui effectue une recopie d’un processus en mémoire, les
_threads_ ne dupliquent que les information relatives à l’exécution.
Lors de la création de threads par un processus, les threads possèderont le même
PID, mais des identifiants de threads différents : TID.

- Option de compilation : `-lpthread`
- Include : `pthread.h`

Rappels des prototypes utiles :
```c
int pthread_create(pthread_t * restrict thread,
		   const pthread_attr_t * restrict attr,
		   typeof(void *(void *)) * start_routine, void *restrict arg);
pthread_t pthread_self(void);
int pthread_join(pthread_t thread, void **retval);
int pthread_detach(pthread_t thread);
void pthread_exit(void *retval);
int pthread_cancel(pthread_t thread);
int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldtype);
```


Exercices
---------

1. Soit le programme suivant :

```c
#include <stdio.h>
#include <pthread.h>

pthread_t pthread_id[3];

void *f(void*)
{
	int j = 0, k = 0;

	for (j = 0; j < 3; j++) {
		for (k = 0; k < 100000; k++) ;
		printf("pthread de numero %d, j=%d\n", pthread_self(), j);
		fflush(stdout);
	}
}

main()
{
	int i;
	for (i = 0; i < 3; i++) {
		if (pthread_create(pthread_id + i, NULL, f, i) == -1) {
			fprintf(stderr, "Erreur creation pthread numero %d\n",
				i);
			exit(2);
		}
	}
	printf("Je suis la pthread initiale du processus et
          j'ai comme numero %d\n", pthread_self());
	printf("Je suis la pthread initiale et je me termine \n");
}
```

   a. Expliquer la sortie suivante, résultant de l’exécution du programme précédent :

```
pthread de numero 1025, j=0
pthread de numero 1025, j=1
pthread de numero 1025, j=2
pthread de numero 2050, j=0
pthread de numero 2050, j=1
pthread de numero 2050, j=2
pthread de numero 3075, j=0
Je suis la pthread initiale du processus et j'ai comme numero 1024
Je suis la pthread initiale et je me termine
```

   b. Que faut-il modifier pour obtenir l’ensemble des affichages ?


2. Écrire un programme qui lance 3 threads, chacun affichant son TID et son PID.

3. Écrire un programme qui crée 5 threads (en plus du thread initial), et fait
   exécuter à chacun une fonction `tache(void *i)` pour `i` entier allant de 1
   à 5. Dans cette fonction, faire un boucle vide de 10'000 étapes, puis
      l’affichage à l’écran du numéro `i` et du TID. Le thread initial réalisera
      également l’affichage. Vérifier sur cet exemple que :
      - L’utilisation de la foncion `exit()` dans un des threads du processus
        entraîne la terminaison de l’ensemble des threads.
      - La terminaison du thread initial entraîne la libération de toutes les
        ressources, donc la terminaison de l’ensemble des threads du processus.
        Comment éviter cette terminaison prématurée ?

4. Que se passe-t-il lorsqu’un processus ayant plusieurs threads fait un
   `fork()` dans l’un de ses threads, les threads sont-ils dupliqués ? Tester
   avec un appel bloquant sur l’entrée standard (lecture) et un thread qui fait
   le `fork()`.

5. Écrire sa version de `ls` : pour chaque répertoire donné en argument, un
   thread sera créé et affichera la taille et le nom des fichiers présents. On
   utilisera les appels suivants :
   ```c
   #include <sys/types.h>
   #include <unistd.h>
   #include <dirent.h>

   DIR *opendir(const char *name);
   struct dirent *readdir(DIR *dirp);
   int closedir(DIR *dirp);
   ```
   Modifier le programme afin qu’il affiche la taille (lisible par des humains
   (avec les préfixes SI ou binaires)) totale des fichiers présents dans
   l’arborescence du répertoire (équivalent de `du -h -s`).
   Modifier le programme pour que l’utilisateur·ice ait le choix de l’affichage,
   et donc *parser* les options de la ligne de commande, pour se faire, on
   pourra utiliser la fonction dédiée de `unistd.h` :
   ```c
   int getopt(int argc, char *argv[], const char *optstring);
   ```
   Ajouter quelques autres options : dossiers toujours en premier, tri
   alphabétique, colorisation (en fonction du type de fichier, et de si on écrit
   dans le tampon du terminal ou dans un tuyau), tri temporel (date de création,
   de dernière modification), …
