18
Jan
09

Eviter la race condition


Lorsque l’on développe avec des modules asynchrones, on s’expose au risque de race condition, souvent sans le savoir. J’en ai fait les frais il y a peu alors que je m’amusais joyeusement avec le jQuery et l’ajax. Je me suis dit que cela serait intéressant de détailler ici ce qui s’est passé afin d’éviter aux développeurs de faire face au même problème.

Mais qu’est ce qu’une race condition? Une race condition, c’est une condition particulière qui se produit de manière aléatoire (d’où la difficulté à la reconnaître et à la débugger). Son apparition est essentiellement liée à des vitesses différentes de processing entre plusieurs threads qui font que parfois, on tombera dedans et parfois pas.

Pour expliquer tout cela dans les détails, voici un exemple concret. Imaginons une page web contenant un tableau d’où on va retirer des éléments. Ces éléments sont liés à une BDD mysql. Lorsque l’on retire les éléments du tableau, cela génère un appel Ajax (asynchrone) qui va supprimer les éléments dans la base de données. Pendant ce temps, notre script continue à s’exécuter côté client et il génère un autre appel Ajax pour aller lire la BDD mysql qui cette fois-ci va aller la lire la table sql dont on a retiré les éléments pour ensuite rafraîchir la table côté client. Le problème est que comme on fait face à un processus asynchrone, il est tout à fait possible que le processus lancé en premier se termine après le début de l’exécution du second. Dans ce cas, on fait face à une race condition car la vision pour le second processus n’est pas celle qu’on souhaite puisqu’il va lire la table avant sa mise à jour.

Il existe plusieurs solutions plus ou moins propres et optimales pour éviter la race condition :

1/ Utiliser des appels Ajax synchrones (c’est une option du $.ajax). Ainsi, tant que le premier appel ne sera pas terminé, il ne commencera pas le second;

2/ Simuler la synchronisation des appels Ajax en lançant le second dans la fonction de retour du premier;

3/ Faire toutes les opérations mysql dans le même appel Ajax;

4/ Utiliser une variable initialisée avant le premier appel Ajax et mise à jour dans sa fonction de retour. Ensuite, on ne commence pas le second appel tant que cette variable n’est pas mise à jour par la fonction de retour (avec un setTimeout par exemple).

Les deux schémas ci-dessous réalisés pour l’occasion illustrent ce propos :

race-condition-scenario

scenario-sans-race-condition

Le concept de race condition est un concept applicable à tous les processus informatiques asynchrones d’une manière générale. Il convient donc d’ouvrir l’oeil et d’y penser à deux fois lorsque l’on programme en utilisant des appels asynchrones (ajax ou autres). En effet, vous passerez énormément de temps à comprendre que vous faites face à une race condition car lorsque notre cerveau ordonne des instructions de manière logique, il a dû mal à comprendre que l’ordinateur ne suive pas tout à fait la même logique. Le fait est qu’ici, on fonctionne avec des threads, chaque thread étant indépendant de l’autre…





2 commentaires pour “Eviter la race condition”
  1. Benjamin dit :

    Sympa cette explication.
    Attention, si l’action 2 est faite par un utilisateur, alors il faut penser a empêcher l’utilisateur de faire l’action 2 tant que l’action 1 n’est pas fini.
    Sinon attention, à la race condition

  2. Olivier dit :

    Tu as tout à fait raison, ceci dit, à part les crons, tout est plus ou moins généré par une action utilisateur…


L'autre monde | Thème liquide par Olivier