Adloun

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 :

attenduobtenu (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.