Le compteur perdu, mesuré
Exercice · niveau 2 · informatique (MP2I/MPI), chapitre 22 — Concurrence et synchronisation
Énoncé
Deux fils incrémentent fois un compteur partagé, sans protection. Quelle valeur obtient-on ? Et avec quatre fils ?
Corrigé
Loin du compte, et jamais deux fois la même. Dix exécutions de chaque, mesurées :
| attendu | obtenu (dix exécutions) | |
|---|---|---|
| fils | à | |
| fils | à |
Ce ne sont pas quelques incréments perdus : c'est la moitié, puis les trois quarts. Avec quatre fils, on obtient à peine plus qu'avec deux — ajouter des fils n'ajoute presque rien, car ils s'écrasent mutuellement.
Le mécanisme, tel que le cours le décrit. La ligne compteur = compteur + 1 se décompose en trois opérations machine : lire, ajouter, écrire. Si deux fils lisent la même valeur , tous deux écriront : un incrément a disparu. Sur des dizaines de milliers de tours, cela se produit constamment.
Pourquoi le résultat est-il si stable autour de ? Parce que le nombre obtenu est, en gros, le nombre d'incréments du dernier fil à écrire, plus ce que les autres ont eu le temps de faire pendant leurs tranches d'ordonnancement. Le résultat n'est ni « moins quelques-uns » ni aléatoire : il est structurellement voisin de . Un résultat faux peut être régulier, et cette régularité est trompeuse : elle ressemble à un résultat.
En pratique — La seule correction : protéger la section critique
pthread_mutex_t verrou = PTHREAD_MUTEX_INITIALIZER;
void* incrementer(void* arg) {
for (int i = 0; i < 100000; i = i + 1) {
pthread_mutex_lock(&verrou);
compteur = compteur + 1; /* SECTION CRITIQUE */
pthread_mutex_unlock(&verrou);
}
return NULL;
}
Mesuré : exactement, sur cinq exécutions avec quatre fils. Le problème 22.1 mesure ce que cette protection coûte — et montre qu'on peut la payer bien moins cher.
Les autres exercices de ce chapitre Le cours du chapitre
Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.