Peterson algorithme en Java?
Est-il par exemple de la mise en œuvre de l'algorithme de Peterson pour l'exclusion mutuelle dans Java?
- N'hésitez pas à poster vos propres réponses, je suis à la recherche pour le meilleur!
- Voulez-vous dire Peterson de l'algorithme pour la mise en œuvre de l'exclusion mutuelle avec seulement de la mémoire partagée avec des hypothèses fortes? Je doute que Java du modèle de mémoire (ou toute autre langue moderne assez explicitement de donner un modèle de mémoire) permet de Peterson algorithme de travailler... Et si vous allez utiliser des barrières de la mémoire, pourquoi ne pas utiliser la synchronisation des instructions fournies par le langage?
- Cuoq je ne suis pas sûr, pouvez-vous m'indiquer papier original sur cet algorithme, afin que je puisse vérifier? Quelles conditions préalables doivent être satisfaites par le modèle de mémoire sémantique pour assurer algorithme correct? La raison de la non utilisation de la simultanéité et de la synchronisation des mécanismes fournis par Java est simplement que je suis en train d'essayer de comprendre Petersons algorithme, ne sont pas simultanées de programmation en Java.
- L'algorithme est si courte (l'article original est célèbre pour être seulement 2 pages) qu'il est entièrement sur la page Wikipédia: en.wikipedia.org/wiki/Peterson%27s_algorithm . Voir la "Note" à l'article trop.
- Cuoq j'ai lu l'article, mais je ne pouvais pas trouver aucune mention de la "hypothèses fortes". Donc si j'ai bien compris le problème ici c'est que la possibilité de réordonner les accès à la mémoire?
- Vous avez raison, le problème est l'accès à la mémoire de réorganisation. L'article est antérieur à l'optimisation des implémentations de multi-CPU / multi-core. Le DEC Alpha concepteurs ont été les premiers à affaiblir l'idée d'un seul mémoire partagée vues par tous les processeurs/cœurs/threads. Cette "unique et cohérente de la mémoire partagée" l'hypothèse est implicite (mais clairement fait) dans l'article.
- Cuoq ah, maintenant je comprends ce que tu ment, merci:)
Vous devez vous connecter pour publier un commentaire.
Personne ici n'a fourni une correcte et sûre de la mise en œuvre de cet algorithme en Java. Je ne suis pas sûr de savoir comment John W la solution est censé marcher, car il a des pièces manquantes (à savoir les déclarations de la ThreadLocals et une explication de ce qui est censé être dans son tableau de primitif
booleans
n'ont pasget()
etset()
).Le chapitre 17 de la Spécification du Langage Java explique la Java du modèle de mémoire. D'intérêt particulier est Section 17.4.5, qui décrit la se passe-avant commande. Il est assez facile de penser dans un seul thread. Considérons l'extrait de code:
Tout le monde sera d'accord qu'à la fin de cet extrait, les deux
x
etz
sont égales à0
et les deuxy
etw
sont égales à5
. Ignorant les déclarations, nous avons six actions ici:x
y
x
z
y
w
Parce qu'ils apparaissent tous dans le même thread, JL dit que ces lectures et écritures sont garantis à exposer cette commande: chaque action n ci-dessus (parce que les actions sont dans un seul thread) est un passe-avant relation avec toutes les actions m, m > n.
Mais ce sur les différents threads? Pour champ normal d'accès, il n'y a aucun passe-avant les relations établies entre les threads. Cela signifie qu'un Thread peut incrémenter une variable partagée et le Fil B peut lire que variable, mais de ne pas voir la nouvelle valeur. Dans l'exécution du programme dans la JVM, la propagation de Fil d'Une écriture peut avoir été réorganisées à se produire après que le Thread B lire.
En fait, le Thread A pu écrire dans une variable
x
, puis à une variabley
, l'établissement d'un passe-avant la relation entre ces deux actions, au sein de Filetage A. Mais le Fil B peut lirex
ety
et il est légal pour B pour obtenir la nouvelle valeur dey
avant la nouvelle valeur dex
s'affiche. La spécification dit:Comment pouvons-nous résoudre ce problème? Pour le champ normal accède, l'
volatile
mot-clé est assez:synchronise avec est une condition plus forte que se passe-avant, et depuis que se passe-avant est transitive, si Un Thread veut Thread B pour voir sa écrit à
x
ety
, il a juste besoin d'écrire dans une variable volatilez
après avoir écritx
ety
. Le fil B à lire à partir dez
avant de lirex
ety
et il sera assuré de voir les nouvelles valeurs dex
ety
.Gabriel solution, nous voyons ce modèle: une écriture se produit à
in
, qui ne serait pas visible pour les autres threads, mais alors une écriture se produit àturn
, de sorte que les autres threads sont garantis à voir à la fois écrit, aussi longtemps qu'ils lireturn
premier.Malheureusement, le tout en boucle conditionnelle est à l'envers: pour garantir un thread ne voit pas de données obsolètes pour
in
, la boucle while devrait se lire deturn
première:Avec ce correctif à l'esprit, la plupart du reste de la solution est ok: dans la section critique, nous ne nous soucions pas de caducité de données parce que, eh bien, nous sommes dans la section critique! Le seul autre défaut vient à la fin: l'Exécutable jeux de
in[id]
une nouvelle valeur, et les sorties. Les autres Thread être assuré de voir la nouvelle valeur dein[id]
? La spécification dit pas:Alors, comment pouvons-nous résoudre ce problème? Juste ajouter une autre écriture de
turn
à la fin de la méthode:Depuis nous avons réorganisé le tout en boucle, l'autre thread sera assuré de voir la nouvelle valeur fausse de
in[id]
parce que l'écriture dein[id]
se passe-avant de l'écrire àturn
se passe-avant de le lire à partir deturn
se passe-avant de le lire à partir dein[id]
.Inutile de dire que, sans une métrique tonne de commentaires, cette méthode est fragile et si quelqu'un pourrait venir le long et changer quelque chose et subtilement briser l'exactitude. Juste de la déclaration du tableau
volatile
n'est pas assez bon: comme expliqué dans ce fil par le projet de Loi Pugh (l'un des chercheurs pour le Java modèle de mémoire), déclaration d'un tableauvolatile
met à jour le tableau référence visible pour les autres threads. Les mises à jour des éléments du tableau ne sont pas nécessairement visibles (donc, toutes les boucles que nous avons juste eu à passer à travers en utilisant un autrevolatile
variable à la garde de l'accès aux éléments du tableau).Si vous voulez que votre code d'être clair et concis, gardez-le comme il est et le changement
in
être un AtomicIntegerArray (utilisez 0 pour false, 1 pour vrai; il n'y a pas de AtomicBooleanArray). Cette classe se comporte comme un tableau dont les éléments sont tousvolatile
, et permettra de résoudre tous nos problèmes bien. Alternativement, vous pouvez simplement déclarer deux variables,boolean in0
etboolean in1
, et de les mettre à jour au lieu d'utiliser un booléen tableau.Sauf si vous avez des besoins spécifiques pour Peterson agorithm (ce qui serait étrange quand on travaille dans un langage de haut niveau comme Java), je vous suggère de prendre un coup d'oeil à la synchronisation des installations construites dans la langue.
Par exemple, vous pouvez trouver ce livre chapitre sur "les Conditions de Course et
Exclusion mutuelle" en Java utile: http://java.sun.com/developer/Books/performance2/chap3.pdf
Dans particlar:
Je ne pouvais pas en trouver un sur le web, moi-même, j'ai donc décidé d'essayer de l'écrire:
N'hésitez pas à commenter, il sera apprécié:)
Vous devriez vraiment vérifier le livre l'Art de La Programmation Multiprocesseur. Il dans de grands détails sur les différentes implémentations de verrouillage (les deux spin, et le blocage). Il se rend également sur différents autres types de connexions simultanées algorithmes (passez à la liste par exemple). Voici un extrait de son livre sur la Peterson Verrouillage de l'algorithme
Alors que les paterson algo, le AtomicBoolean et Atomique* classes utilisent l'approche de lockless, occupé les boucles de mise à jour de données partagée. Ils peuvent répondre à vos exigences.