Concurrent programming for gem-graph 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."