Merge branch 'Jean-master-patch-99793' into 'master'
Concurrent Programming No race condition ? See merge request gem-graph-team/gem-graph!14
This commit is contained in:
commit
42d2bacac5
|
@ -3,8 +3,8 @@ Concurrent programming for gem-graph
|
||||||
Le thread maître, dans l'ordre:
|
Le thread maître, dans l'ordre:
|
||||||
(1) - cherche, en un temps fini, un espace local dans l'espace global de préemption et, s'il le trouve:
|
(1) - cherche, en un temps fini, un espace local dans l'espace global de préemption et, s'il le trouve:
|
||||||
+ tente, en un temps fini, de le préempter et, si la préemption a été possible,
|
+ tente, en un temps fini, de le préempter et, si la préemption a été possible,
|
||||||
+ crée un thread de calcul en lui communiquant l'adresse de cet espace local
|
+ tente, en un temps fini, de réserver une place dans la liste des threads
|
||||||
+ et l'inscrit dans la liste des threads)
|
+ en cas de succès, crée un thread de calcul en lui communiquant les adresses
|
||||||
|
|
||||||
(2) - cherche, en un temps fini, dans la liste des threads s'il y a qui ont fini leur calcul et, s'il y en a:
|
(2) - cherche, en un temps fini, dans la liste des threads s'il y a qui ont fini leur calcul et, s'il y en a:
|
||||||
+ lève la préemption de leur espace local et
|
+ lève la préemption de leur espace local et
|
||||||
|
@ -13,17 +13,18 @@ Le thread maître, dans l'ordre:
|
||||||
(3) - affiche les résultats.
|
(3) - affiche les résultats.
|
||||||
|
|
||||||
Chaque thread de calcul, dans l'ordre:
|
Chaque thread de calcul, dans l'ordre:
|
||||||
(1) - lit son espace local et les règles écrites dans l'arbre des transitions et les compare.
|
(1) - lit son espace local graphique et les règles écrites dans l'arbre des transitions et les compare.
|
||||||
(pour faire ce calcul, il n'écrit que dans des variables locales)
|
(pour faire ce calcul, il n'écrit que dans des variables locales)
|
||||||
si échec, il se termine, sinon:
|
si échec, il se termine, sinon:
|
||||||
|
|
||||||
(2) - écrit le résultat de son calcul dans l'espace global si une règle peut être appliquée.
|
(2) - si une règle peut être appliquée, é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.
|
(3) - dans tous les cas, écrit qu'il est terminé dans une liste où le thread maître peut lire et écrire.
|
||||||
si succès, cette écriture est sa dernière instruction. (après, il est terminé)
|
cette écriture est sa dernière instruction. (après, il est terminé)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
> engine (top-level) boucle infinie:
|
> engine (top-level ?) > thread maître en boucle infinie:
|
||||||
|
|
||||||
opération type ressource thread maître thread de calcul
|
opération type ressource thread maître thread de calcul
|
||||||
--------- ---- ---------- ------------- ----------------
|
--------- ---- ---------- ------------- ----------------
|
||||||
|
@ -35,11 +36,11 @@ préemption espace local section critique espace global de préemption
|
||||||
si confirmation: boucle finie espace global de préemption écriture
|
si confirmation: boucle finie espace global de préemption écriture
|
||||||
fin section c. espace global de préemption ouverture verrou
|
fin section c. espace global de préemption ouverture verrou
|
||||||
si succès préemption:
|
si succès préemption:
|
||||||
création d'un thread section critique liste des threads fermeture verrou
|
recherche d'une place thread section critique liste des threads fermeture verrou
|
||||||
boucle finie liste des threads lecture
|
boucle finie liste des threads lecture
|
||||||
si succès, assignment liste des threads écriture
|
si succès, assignment liste des threads écriture
|
||||||
fin section c. liste des threads ouverture verrou
|
fin section c. liste des threads ouverture verrou
|
||||||
assignment mémoire / CPU système écriture
|
si succès, création d'un thread assignment mémoire / CPU système écriture
|
||||||
|
|
||||||
recherche règle de transition parcours d'arbre arbre des transitions lecture
|
recherche règle de transition parcours d'arbre arbre des transitions lecture
|
||||||
espace global graphique lecture
|
espace global graphique lecture
|
||||||
|
@ -51,9 +52,9 @@ terminaison d'un thread section critique liste des threads
|
||||||
fin section c. liste des threads ouverture verrou
|
fin section c. liste des threads ouverture verrou
|
||||||
fin du thread
|
fin du thread
|
||||||
|
|
||||||
levée préemption espace local section critique liste des threads fermeture verrou
|
recherche place espace local section critique liste des threads fermeture verrou
|
||||||
boucle finie liste des threads lecture
|
boucle finie liste des threads lecture
|
||||||
si succès, assignment liste des threads écriture
|
si succès, levée préemption assignment liste des threads écriture
|
||||||
fin section c. liste des threads ouverture verrou
|
fin section c. liste des threads ouverture verrou
|
||||||
|
|
||||||
thread d'affichage boucle finie recherche résultats lecture
|
thread d'affichage boucle finie recherche résultats lecture
|
||||||
|
@ -65,35 +66,22 @@ Trois ressources doivent être accessibles aux threads de calcul de l'automate:
|
||||||
- l'état local (c-a-d: une partie de l'espace global préemptée) pour:
|
- l'état local (c-a-d: une partie de l'espace global préemptée) pour:
|
||||||
(1) lire les contraintes nécéssaires pour le choix de la règle de transition
|
(1) lire les contraintes nécéssaires pour le choix de la règle de transition
|
||||||
(2) puis écrire le résultat de son calcul en cas de succès
|
(2) puis écrire le résultat de son calcul en cas de succès
|
||||||
|
- la liste des threads en écriture pour indiquer au thread maître qu'ils vont se terminer
|
||||||
|
|
||||||
Le thread n'est crée que si la préemption a été possible
|
Un thread de calcul n'est crée que si la préemption a été possible.
|
||||||
Son calcul aboutit au choix de l'une des règles ou échoue
|
Son calcul aboutit au choix de l'une des règles ou échoue.
|
||||||
comme les threads ont seulement besoin de lire l'arbre des règles pendant leur calcul.
|
Comme les threads ont seulement besoin de lire l'arbre des règles pendant leur calcul,
|
||||||
Ces lectures ne causent pas de risque de race condition.
|
leurs lectures ne causent pas de risque de race condition.
|
||||||
|
|
||||||
L'espace global de préemption et la liste des threads sont les seuls objets où plusieurs threads doivent écrire:
|
La liste des threads est le seul objet 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
|
- le thread maître au début du calcul (quand il a préempté et va créer un thread) et
|
||||||
- chaque thread doit écrire dans les deux quand il finit son calcul :
|
- chaque thread quand il va se finir (pour que le thread maître sache qu'il peut lever la préemption)
|
||||||
+ son résultat dans l'espace global (si son calcul a abouti) 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:
|
Un point délicat est qu'il ne faut pas que l'espace global de préemption soit modifié entre:
|
||||||
- le thread maître a acquis l'espace global de préemption et attend pour la liste des threads
|
|
||||||
- un thread de calcul a acquis la liste des threads et attend pour l'espace global de préemption
|
|
||||||
|
|
||||||
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 est coûteuse en temps d'attente.
|
|
||||||
|
|
||||||
Le point délicat est qu'il ne faut pas que l'espace global de préemption soit modifié entre:
|
|
||||||
- le moment où le thread maître vient de trouver un espace local convenable et
|
- 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.
|
- le moment où il a fini de préempter cet espace local.
|
||||||
|
Il faut donc qu'il soit vérifié après mise en place du verrou sur l'espace global
|
||||||
|
et avant préemption (et levée du verrou)
|
||||||
|
|
||||||
Il ne semble pas y avoir de risque entre:
|
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ù un thread de calcul a fini de modifier son espace local, et
|
||||||
|
@ -102,5 +90,8 @@ Il ne semble pas y avoir de risque entre:
|
||||||
La préemption et sa levée doivent être des opérations atomiques
|
La préemption et sa levée doivent être des opérations atomiques
|
||||||
|
|
||||||
David Beazley & Brian K.Jones Python Cookbook 2013 p503:
|
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."
|
"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."
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue