diff --git a/Concurrent Programming b/Concurrent Programming new file mode 100644 index 0000000..c4bcb7a --- /dev/null +++ b/Concurrent Programming @@ -0,0 +1,59 @@ +deux ressources doivent être accessibles aux threads de calcul de l'automate: +- les transitions (c-a-d: l'arbre des règles) + + car chaque thread de calcul doit choisir l'une d'entre elles +- l'état local (c-a-d: une partie de l'espace global préemptée) + + que le thread doit lire pour choisir la règle de transition + + et où il doit écrire le résultat de son calcul en cas de succès + (le thread n'est crée que si cette préemption a été possible) + +puisque les threads lisent seulement l'arbre des règles pendant leur calcul, +et que le seul objet dans lequel ils doivent écrire est l'espace global, +il y n'y a pas de risque de race condition du fait de leurs opérations de calcul. + +le thread maître +(1) - cherche un espace local dans l'espace global et, s'il le trouve, le préempte. +(2) - crée un thread de calcul en lui communiquant l'adresse de cet espace local. +(3) - cherche s'il y a des threads qui ont fini leur calcul et, s'il y en a, +(4) - lève la préemption de leur espace local et les retire de la liste des threads. +les recherches (1) et (3) doivent s'effectuer en un temps fini. + +le thread de calcul +(1) - cherche si une règle peut s'appliquer à son espace local. + (pour faire ce calcul, il n'écrit que dans des variables locales) +(2) - écrit le résultat de son calcul dans l'espace global. +(3) - écrit qu'il est terminé dans une liste où le thread maître peut lire et écrire. + cette écriture est sa dernière instruction. (après, il est terminé) + +L'espace global et la liste des threads sont donc les seuls objets où plusieurs threads doivent écrire: +- le thread maître doit écrire dans les deux au début du calcul (quand il préempte et crée un thread) et +- chaque thread doit écrire dans les deux quand il finit son calcul (si son calcul a abouti) : + + son résultat dans l'espace global et + + son état dans la liste des threads (sinon, le thread maître ne saura pas qu'il peut lever la préemption) + +Des deadlocks sont possibles si: +- le thread maître a acquis l'espace global et attend pour la liste des threads +- un thread de calcul a acquis la liste des threads et attend pour l'espace global + +Mais si les acquisitions se font dans le même ordre pour tous les threads (maître et calcul): +en premier l'espace global et en second la liste des threads, alors il ne peut y avoir de deadlock +car aucun thread ne pourra à verrouiller la liste des threads tant qu'il n'a pas eu accès à l'espace global. + +Une première solution est donc de ne réaliser que simultanément l'ensemble des opérations +sur l'espace global et la liste des threads (en début comme en fin de calcul) +et de ne les réaliser que lorsque les deux ressources ont été acquises +par le thread maître en début de calcul ou par le thread de calcul lorsqu'il a fini. +Cette solution peut être coûteuse en temps d'attente. + +Le point délicat est qu'il ne faut pas que l'espace global soit modifié entre: +- le moment où le thread maître vient de trouver un espace local convenable et +- le moment où il a fini de préempter cet espace local. + +Il ne semble pas y avoir de risque entre: +- le moment où un thread de calcul a fini de modifier son espace local, et +- le moment où le thread maître lève la préemption associée + +La préemption et sa levée doivent être des opérations atomiques + +David Beazley & Brian K.Jones Python Cookbook 2013 p503: +"The solution in which locks are always acquired in strict order [...] can be mathematically proven to avoid deadlocks [because] you can't get cyclic locking dependencies, which are a necessary condition fordeadlock to occur." +