Quels sont les vrais dangers de la lecture / écriture simultanée à une seule variable? p>
Si j'utilise un fil pour écrire une variable et une autre pour lire la variable dans une boucle de While et il n'y a pas de danger si la variable est lue tout en étant écrite et qu'une vieille valeur est utilisée, ce qui est un danger ici? p>
Une lecture / écriture simultanée peut-elle causer un crash de fil ou ce qui se passe au niveau bas lorsqu'une lecture / écriture simultanée exacte se produit? P>
8 Réponses :
En général, vous obtenez des résultats inattendus. Wikipedia définit deux conditions de course distinctes: p>
Une course critique se produit lorsque la commande dans laquelle les variables internes sont modifiées détermine l'état éventuel que la machine d'état se retrouvera dans. P>
Une race non critique se produit lorsque l'ordre dans lequel les variables internes sont modifiées ne modifie pas l'état éventuel. En d'autres termes, une race non critique se produit lors du passage à l'état souhaité signifie que plusieurs variables d'état internes doivent être modifiées à la fois, mais peu importe dans quel ordre ces variables d'état internes changent, l'état résultant sera le même. p> blockQuote>
La sortie ne sera donc pas toujours gâchée, cela dépend du code. C'est une bonne pratique pour
TOUJOURS STRAND> TRANSFERT DES CONDITIONS DE RACINGS POUR UNE ÉTAPE DU CODE PLUS ÉTAPES ET PREPENDUER DES ERREURS POSSIBLES. Rien n'est plus gênant alors de ne pas pouvoir faire confiance à vos propres données. P>
Vous pouvez également utiliser des opérations atomiques. Un mutex peut bien être surkill.
@Deadmg: Je quitterais des opérations atomiques lorsque l'OP a interné la nécessité de Mutilex (c'est-à-dire le faire, puis le faire correctement, puis le faire rapidement, les mutiles étant bien le font bien, les opérations atomiques étant le font vite).
J'ai changé le libellé à la "affaire plus générale des conditions de course".
Deux threads lisant la même valeur ne sont pas un problème du tout. P>
Le problème commence lorsqu'un thread écrit une variable non atomique et un autre fil le lit. Ensuite, les résultats de la lecture sont indéfinis. Puisqu'un fil peut être préempté (arrêté) à tout moment. Seules les opérations sur les variables atomiques sont garanties pour être non cassables. Les actions atomiques écrit généralement sur Si vous avez deux threads accédant aux mêmes données, il est la meilleure pratique + généralement inévitable d'utiliser le verrouillage (mutex, sémaphore). P>
htth p>
Mario P> INT code> de type variables. P>
@ Helium3: Cela dépend de la CPU. En outre, les variables doivent être alignées.
Si la variable étant écrite et à partir de ne peut pas être mise à jour ou lecture atomique, il est possible que le lecteur ait récupéré une valeur corrompue "partiellement mise à jour". p>
Que se passe-t-il quand par exemple un chèque comme suit alors que (IntTValue == 0) et le fil écrit la valeur INT est occupé à écrire IntTValue = 1;
@Andrei: Non. Juste un Int normal.
Ensuite, code postal :) Sans volatilité ou une barrière de mémoire, je doute que le thread de lecteur verra la sortie de fil d'écriture en raison de la mise en cache.
Eh bien, il le voit quand je l'exécuterai maintenant. Je ne veux tout simplement pas vouloir des problèmes imprévus tels qu'un accident de fil. Cette question est plus concernant le fonctionnement interne des threads et le système
pthread_mutex_unlock () code> contient une barrière de mémoire implicite). LI>
ul>
dépend de la plate-forme. Par exemple, sur Win32, puis lus et écrire des ops de valeurs 32 bits alignés sont atomiques, c'est-à-dire que vous ne pouvez pas lire une nouvelle valeur et demi-lecture une valeur ancienne, et si vous écrivez, alors quand quelqu'un vient lire , soit ils obtiennent toute la nouvelle valeur ou la valeur ancienne. Ce n'est pas vrai pour toutes les valeurs, ou toutes les plates-formes, bien sûr. P>
@ Hélium3: ce comportement est réellement pour x86.
Le pire qui va arriver dépend de la mise en œuvre. Il y a tellement de mises en œuvre totalement indépendantes de Pthreads, en cours sur différents systèmes et matériels, que je doute que quiconque connaisse tout ce qui concerne tous.
si dans une seule vérification de dans la pratique, sur un système multi-processu qui n'a pas Caches de mémoire cohérentes, cela pourrait être très longtemps avant que la boucle voit jamais un changement de processeur différent, car sans barrières de mémoire, il ne peut jamais mettre à jour sa vue en cache de la mémoire principale. Mais Intel a des caches cohérentes, si probablement que vous ne verrez personnellement aucun retard suffisamment longtemps pour vous soucier. Si un peu pauvre essaie jamais d'exécuter votre code sur une architecture plus exotique, ils peuvent finir par avoir à le corriger. P> retour à la théorie, la configuration que vous décrivez pourrait em> causer un crash. Imaginez une architecture hypothétique où: p> Bang, un comportement non défini, vous lisez une représentation piège. Il se peut que POSIX interdit certaines représentations de pièges que la norme C permet, auquel cas p code> n'est pas un pointeur à volatile puis Je pense qu'un compilateur pour une implémentation de POSIX conforme est autorisé em> à tourner: p>
* p code > suivi d'une boucle infinie qui ne prend pas la peine de regarder la valeur du
* p code> du tout. En pratique, il ne sera donc pas question de savoir si vous souhaitez programmer à la norme ou au programme de comportement observé sans papiers des implémentations que vous utilisez. Ce dernier fonctionne généralement pour des cas simples, puis vous construisez sur le code jusqu'à ce que vous fassiez quelque chose de compliqué suffisant pour que cela ne fonctionne pas de manière inattendue. P>
p code> pointe vers un type non atomique, comme
long long code> sur une architecture typique de 32 bits. Li>
long long code> sur ce système comporte des représentations de piège, par exemple parce qu'il a un bit de rembourrage utilisé comme une vérification de parité. LI>
* p code> est à moitié terminée lorsque la lecture se produit li>
long long code> pourrait ne pas être un exemple valide pour le type de
* P code>, mais je m'attends Vous pouvez trouver un type pour quelles représentations de pièges sont autorisées. p> p>
Super. Il fonctionne actuellement sur mon Mac Intel 64 Bit, mais il sera déployé sur une planche à panda (bras double core) exécutant Ubuntu.
@ Hélium3: AH, bras à double core, qui peut ne pas avoir de cache cohérente. Je ne suis pas à jour avec le bras, mais il y a quelques années, je suis sûr qu'il y en avait à propos de la vérification.
La variable est une valeur in int. Aucun pointeur ou quoi que ce soit autre que INT.
@ Helium3, "fonctionne actuellement" ... Êtes-vous sûr de tester suffisamment pour capturer le boîtier un sur un milliard? Utilisez une instruction d'échange atomique pour cela, vous trouverez facilement du code pour cela pour différentes architectures de la CPU. Ce n'est qu'alors que vous auriez une garantie.
@ Helium3: Il peut être plus efficace d'avoir le fil de travail poster un sémaphore que le fil de surveillance attend. Ensuite, vous n'avez pas le fil de chien de garde occupé-boucle (ou même la boucle de sommeil).
résultat n'est indéfini.
considère ce code: p> problème est que si vous avez N threads, le résultat peut être quelque chose entre 10 et N * 10.
En effet, cela pourrait arriver que toutes les bandes de roulement se lisent la même valeur l'augmentent, puis de l'écriture de la valeur +1. Mais vous avez demandé si vous pouvez planter du programme ou du matériel. Pour résoudre ce problème de verrouillage, vous avez besoin de mutex ou de sémaphore. P> mutex est verrouillé pour le code. En majuscule, vous verrouilleriez une partie du code en ligne p> où sémaphore est verrouillé pour variable p> basicaly Pour résoudre le même type de problème. p> Vérifiez ces outils dans votre bibliothèque de roulement. P>
Ça dépend. Dans la plupart des cas, des résultats erronés sont inutiles. P>
Si deux threads accèdent une variable sans synchronisation appropriée, et au moins une de ces accès est une écriture, vous avez une course de données et un comportement non défini. P>
Comment les manifestations de comportement non définies sont entièrement de la mise en œuvre dépendante. Sur la plupart des architectures modernes, vous n'obtiendrez pas un piège ou une exception ou quoi que ce soit du matériel, et il sera lu E.g. Avec deux threads incrémentant une variable, vous pouvez manquer des comptes, comme décrit dans mon article à Devx: http: / /wwww.devx.com/cplus/article/42725 p>
Pour un seul écrivain et un seul lecteur, le résultat le plus courant sera que le lecteur voit une valeur obsolète, mais vous pouvez également voir une valeur partiellement mise à jour si la mise à jour nécessite plus d'un cycle, ou la variable est divisée à travers lignes de cache. Ce qui se passe, cela dépend alors de ce que vous faites avec elle --- Si c'est un pointeur et que vous obtenez une valeur partiellement mise à jour, ce n'est peut-être pas un pointeur valide et ne pointera pas ce que vous avez entendu de toute façon, puis vous pourriez Obtenez une sorte de corruption ou d'erreur due à la déséroférance d'une valeur de pointeur non valide. Cela peut inclure le formatage de votre disque dur ou d'autres conséquences graves si la valeur de pointeur de mauvaise pointe se trouve simplement sur un enregistrement d'E / S mappé de mémoire .... P>
"Une vieille valeur est-elle utilisée" une question assez importante aussi? Qu'est-ce que vous calculez exactement si vous ne vous souciez pas de la valeur de l'une des variables? :RÉ
Vous ne pouvez même pas de manière fiable Nombre i> plus, quel algorithme que vous avez à l'esprit qui peut survivre à changer de variables changent de manière imprévisible? Non, même un générateur de nombres aléatoires ne se qualifie pas.
En boucle de messagerie im en utilisant une condition de travail et une itération supplémentaire ou si la condition tandis que la condition reçoive des données indésirables, elle passerait == 0 et la boucle quittera toute façon. C'est un thread de chien de garde en boucle dans une vérification de la boucle tandis que si le fil est mort. Lorsque la fonction de thread est terminée, il définit la variable = 1 et la boucle tandis que vous quittez.