Question

Sur la plupart des plates-formes courantes (la plus importante étant x86; je comprends que certaines plates-formes ont des modèles de mémoire extrêmement difficiles qui ne fournissent pratiquement aucune garantie utile pour le multithreading, mais je me fiche des contre-exemples rares), est le code suivant sûr?

Sujet 1:

someVariable = doStuff();
atomicSet(stuffDoneFlag, 1);

Sujet 2:

while(!atomicRead(stuffDoneFlag)) {}  // Wait for stuffDoneFlag to be set.
doMoreStuff(someVariable);

En supposant des implémentations standard et raisonnables des opérations atomiques:

  1. L'assignation du fil 1 à someVariable est-elle garantie avant la fin de atomicSet () ?
  2. Thread 2 garantit-il que l'attribution à someVariable a lieu avant d'appeler doMoreStuff () à condition qu'elle lit stuffDoneFlag de manière atomique?

Modifications:

  1. La mise en oeuvre des opérations atomiques que j'utilise contient l'instruction x86 LOCK dans chaque opération, si cela aide.
  2. Supposons que stuffDoneFlag soit correctement effacé. Comment n'est pas important.
  3. Ceci est un exemple très simplifié. Je l'ai créé de cette façon pour que vous n'ayez pas à comprendre tout le contexte du problème pour y répondre. Je sais que ce n'est pas efficace.
Était-ce utile?

La solution

Si votre code x86 actuel a pour magasin storeVariable avant le magasin atomicSet dans le Thread 1 et charge de someVariable après le chargement de atomicRead dans Thread 2, tout devrait bien se passer. Le Manuel du développeur logiciel d'Intel, volume 3A , spécifie le modèle de mémoire pour x86 dans la section 8.2, et les contraintes intra-thread-store-store et load-load devraient suffire ici.

Toutefois, rien n'empêche votre compilateur de réorganiser les instructions générées à partir du langage de niveau supérieur que vous utilisez dans les opérations atomiques.

Autres conseils

1) Oui

2) Oui

Les deux fonctionnent.

Ce code a l’air fileté, mais je doute de l’efficacité de votre spinlock (le temps boucle) à moins que vous ne fassiez tourner que très peu de temps. Il n’ya aucune garantie sur un système donné que Thread 2 n’absorbera pas complètement tout le temps de traitement.

Je recommanderais d'utiliser certaines primitives de synchronisation réelles (qui ressemblent à boost :: condition_variable est ce que vous voulez ici) au lieu de compter sur le verrou de rotation.

Les instructions atomiques garantissent que le thread 2 attend que le thread 1 termine la définition de la variable avant que le thread 2 ne continue. Il existe cependant deux problèmes clés:

1) le someVariable doit être déclaré ' volatile 'pour s'assurer que le compilateur n'optimise pas son allocation, par exemple le stocker dans un registre ou différer une écriture.

2) le second thread se bloque en attendant le signal ( verrouillé en rotation ). Votre plate-forme fournit probablement beaucoup mieux de primitifs et de mécanismes de verrouillage et de signalisation, mais une amélioration relativement simple consisterait simplement à sleep () dans le corps while du fil 2 () .

dsimcha écrit: "Supposons que stuffDoneFlag soit correctement effacé en quelque sorte. Comment est-ce pas important. & Quot; Ce n'est pas vrai!

Voyons le scénario:

  1. Thread2 vérifie le stuffDoneFlag s'il commence à lire someVariable.
  2. Avant que Thread2 ait fini de lire le planificateur de tâches, interrompez sa tâche et suspendez-la pendant un certain temps.
  3. Thread1 à nouveau accéder à someVariable et modifier le contenu de la mémoire.
  4. Le planificateur de tâches rallume Thread2 et continue le travail, mais le contenu de la mémoire de someVariable est modifié!
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top