SE2 : Introduction au multithreading
SE2: Système d'exploitation
Printemps 2024
Instructrices: GUEALIA Nadia


Illustration courtesy of Ecy King, CS110 Champion, Spring 2021
Comment pouvons-nous avoir de la concurrence au sein d’un même processus ?
Objectifs
- Découvrez comment les threads permettent la concurrence au sein d'un même processus
- Comprenez les différences entre les threads et les processus
- Découvrez comment le partage du même espace d'adressage virtuel entre différent threads peut être dangereux
From Processes to Threads
- Le multitraitement (multiprocessing) nous a permis de générer d'autres processus pour effectuer des tâches ou exécuter des programmes
- Puissant ; peut exécuter/attendre d'autres programmes, sécurisé (espace mémoire séparé), communiquer avec des tuyaux (pipes) et des signaux
- Mais limité ; la communication interprocessus est lourde, il est difficile de partager des données/de coordonner
- Existe-t-il un autre moyen d’obtenir une concurrence au-delà du multitraitement qui gère ces compromis différemment ?
Nous pouvons avoir une concurrence au sein d'un même processus en utilisant des threads : des séquences d'exécution indépendantes au sein d'un même processus.
- Les threads nous permettent d'exécuter simultanément plusieurs fonctions de notre programme
- Le multithreading est très courant pour paralléliser les tâches, en particulier sur plusieurs cores
- En C: générez un thread en utilisant pthread_create et spécifiez la fonction que vous souhaitez que le thread exécute (en passant éventuellement des paramètres !)
- Le gestionnaire de threads bascule entre les threads en cours d'exécution comme le scheduler du système d'exploitation bascule entre les processus en cours d'exécution
- Chaque thread fonctionne dans le même processus, ils partagent donc le même espace d'adressage virtuel (!) (Variables globales, texte, données et segments de tas)
- Le segment de pile des processus « stack » est divisé en « ministack » pour chaque thread.
- Il existe de nombreuses similitudes entre les threads et les processus ; en fait, les threads sont souvent appelés processus légers "lightweight processes" .
Multithreading
Processus:
- isoler les espaces d'adressage virtuels (bon : sécurité et stabilité, mauvais : partage d'informations plus difficile)
- peut exécuter facilement des programmes externes (fork-exec) (bien)
- plus difficile de coordonner plusieurs tâches au sein du même programme (mauvais)
Threads:
- partager l'espace d'adressage virtuel (mauvais : sécurité et stabilité, bon : partage d'informations plus facile)
- ne peut pas exécuter facilement des programmes externes (mauvais)
- plus facile de coordonner plusieurs tâches au sein d'un même programme (bien)
Threads vs. Processus
C thread
Un thread peut être généré pour exécuter la fonction spécifiée avec les arguments donnés.
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
//Compile and link with -pthread.- La fonction pthread_create() démarre un nouveau thread dans le processus appelant. Le nouveau thread démarre l'exécution en appelant start_routine(); arg est passé comme seul argument de start_routine().
- start_routine(): la fonction que le thread doit exécuter de manière asynchrone
- arg: une liste d'arguments (zéro ou n'importe quelle longueur ) à passer à la fonction lors de l'exécution
- Une fois créer le thread peut s'exécuter à tout moment !
C thread
Pour plusieurs threads, nous devons attendre un thread spécifique à la fois :
thread treads[5];
...
for (size_t i = 0; i < 5; i++) {
pthread_join(treads[i], NULL);Pour attendre la fin d'un thread, utilisez la fonction pthread_join :
static void * threadFunc(void *arg)
{// instructions
return NULL;
}
//
pthread_t mythread;
pthread_create(&mythread, NULL,threadFunc, NULL);
... // do some work
// Wait for thread to finish (blocks)
pthread_join(mythread, NULL);C thread
Le nouveau thread se termine de l'une des manières suivantes :
-
Il appelle pthread_exit(3), en spécifiant une valeur d'état de sortie qui est disponible pour un autre thread dans le même processus qui appelle pthread_join(3).
-
Il revient de start_routine(). Cela équivaut à appeler pthread_exit(3) avec la valeur fournie dans l'instruction return. -
Il est annulé (voir pthread_cancel(3)). -
L'un des threads du processus appelle exit(3), ou le thread principal effectue un retour depuis main(). Cela provoque la fin de tous les threads du processus.
Terminaison d'un thread:
Notre premier programme Thread
#include <stdio.h>
#include <pthread.h> // for C thread support
static const int kNumFriends = 6;
static void * /* Loop 'arg' times incrementing 'glob' */
greeting(void *arg)
{
printf("Hello, world!\n");
return NULL;
}
int main(int argc, char *argv[]) {
printf("Let's hear from %d threads \n",kNumFriends);
// declare array of empty thread handles
pthread_t friends[kNumFriends];
// Spawn threads
for (size_t i = 0; i < kNumFriends; i++) {
pthread_create(&friends[i], NULL, greeting, NULL);
}
// Wait for threads
for (size_t i = 0; i < kNumFriends; i++) {
pthread_join(friends[i], NULL);
}
printf("Everyone's said hello!\n");
return 0;
}
Our First Threads Program
Our First Threads Program
#include <stdio.h>
#include <pthread.h> // for C thread support
static const int kNumFriends = 6;
static void * /* Loop 'arg' times incrementing 'glob' */
greeting(void *arg)
{
int * iptr =(int*)arg;
printf("Hello, world! I am thread %i \n",*iptr);
return NULL;
}
int main(int argc, char *argv[]) {
printf("Let's hear from %d threads \n",kNumFriends);
// declare array of empty thread handles
pthread_t friends[kNumFriends];
// Spawn threads
for (size_t i = 0; i < kNumFriends; i++) {
pthread_create(&friends[i], NULL, greeting, &i);
}
// Wait for threads
for (size_t i = 0; i < kNumFriends; i++) {
pthread_join(friends[i], NULL);
}
printf("Everyone's said hello!\n");
return 0;
}
Our First Threads Program
C thread
// declare array of empty thread handles
pthread_t friends[kNumFriends];
// Spawn threads
for (size_t i = 0; i < kNumFriends; i++) {
pthread_create(&friends[i], NULL, greeting, &i);
}Nous pouvons créer un tableau de threads comme suit :
Race Conditions (Conditions de course)
- Comme pour les processus, les threads peuvent s’exécuter dans des ordres imprévisibles.
- Une condition de course est un ordre imprévisible d'évènements où certains ordres peuvent provoquer un comportement indésirable.
- Une fonction thread-safe est une fonction qui s'exécutera toujours correctement, même lorsqu'elle est appelée simultanément à partir de plusieurs threads.
- printf n'est pas une fonction thread-safe. Cela signifie par exemple que les affichage peuvent être entrelacées !
Threads Program(en c++)
static const size_t kNumFriends = 6;
static void greeting(size_t i) {
cout << oslock << "Hello, world! I am thread " << i << endl << osunlock;
}
int main(int argc, char *argv[]) {
cout << "Let's hear from " << kNumFriends << " threads." << endl;
// declare array of empty thread handles
thread friends[kNumFriends];
// Spawn threads
for (size_t i = 0; i < kNumFriends; i++) {
friends[i] = thread(greeting, i);
}
// Wait for threads
for (size_t i = 0; i < kNumFriends; i++) {
friends[i].join();
}
cout << "Everyone's said hello!" << endl;
return 0;
}
Les threads partagent la mémoire
- Contrairement aux processus parents/enfants, les threads s'exécutent dans le même espace d'adressage virtuel!
- Cela signifie que nous pouvons par exemple transmettre des paramètres par référence et permettre à tous les threads d'y accéder/de les modifier !
- Pour passer une valeur par référence avec pthread_create, nous devons utiliser le quatrième arguments:
greeting(void *arg)
{
int * iptr =(int*)arg;
...
}
// Spawn threads
for (size_t i = 0; i < kNumFriends; i++) {
pthread_create(&friends[i], NULL, greeting, &i);
}Threads Share Memory
for (size_t i = 0; i < kNumFriends; i++) {
pthread_create(&friends[i], NULL, greeting, &i);
}_start
greeting
main
argc
argv
i
args
args
args
args
args
args
piles de threads
main stack
Ici, nous pouvons simplement passer par copie. Mais faites attention aux conséquences de la mémoire partagée !
Threads Share Memory
Introduction to Multithreading
By NadGy
Introduction to Multithreading
- 100