46 votes

Est-il possible de lire une variable entière qui est modifiée simultanément sans verrouillage ?

Supposons que j'ai une variable entière dans une classe, et que cette variable peut être modifiée simultanément par d'autres threads. Les écritures sont protégées par un mutex. Dois-je également protéger les lectures ? J'ai entendu dire qu'il y a des architectures matérielles sur lesquelles, si un thread modifie une variable, et qu'un autre thread la lit, alors le résultat de la lecture sera un garbage ; dans ce cas, je dois protéger les lectures. Je n'ai jamais vu de telles architectures.

Cette question suppose qu'une transaction unique consiste uniquement à mettre à jour une seule variable entière. Je ne m'inquiète donc pas de l'état des autres variables qui pourraient également être impliquées dans une transaction.

35voto

peterchen Points 21792

lecture atomique
Comme dit précédemment, cela dépend de la plateforme. Sur x86, la valeur doit être alignée sur une frontière de 4 octets. En général, pour la plupart des plateformes, la lecture doit être exécutée en une seule instruction du CPU.

mise en cache de l'optimiseur
L'optimiseur ne sait pas que vous lisez une valeur modifiée par un autre thread. en déclarant la valeur volatile aide à cela : l'optimiseur émettra une lecture/écriture en mémoire pour chaque accès, au lieu d'essayer de garder la valeur en cache dans un registre.

Cache du CPU
Pourtant, vous risquez de lire une valeur périmée, car sur les architectures modernes, vous avez plusieurs cœurs avec un cache individuel qui n'est pas synchronisé automatiquement. Vous avez besoin d'une barrière de lecture de la mémoire, généralement une instruction spécifique à la plate-forme.

Sur Wintel, les fonctions de synchronisation des threads ajouteront automatiquement une barrière de mémoire complète, ou vous pouvez utiliser la commande InterlockedXxxx fonctions.

MSDN : Problèmes de mémoire et de synchronisation , MemoryBarrier Macro

[edit] voir aussi les commentaires de drhirsch.

16voto

hirschhornsalz Points 16306

Vous posez une question sur la lecture d'une variable et vous parlez ensuite de la mise à jour d'une variable, ce qui implique une opération de lecture-modification-écriture.

En supposant que vous voulez vraiment dire la première, la lecture est sûre. s'il s'agit d'une opération atomique . Pour presque toutes les architectures, c'est vrai pour les entiers.

Il y a quelques (et rares) exceptions :

  • La lecture est mal alignée, par exemple l'accès à un int de 4 octets à une adresse impaire. En général, il faut forcer le compilateur, à l'aide d'attributs spéciaux, à effectuer un désalignement.
  • La taille d'un int est plus grande que la taille naturelle des instructions, par exemple en utilisant des ints de 16 bits sur une architecture de 8 bits.
  • Certaines architectures ont une largeur de bus artificiellement limitée. Je n'en connais que de très anciennes et dépassées, comme un 386sx ou un 68008.

8voto

Dmitry Points 3946

Je recommande de ne pas se fier à un compilateur ou à une architecture. dans ce cas.
Lorsque vous avez un mélange de lecteurs et d'auteurs (par opposition à seulement des lecteurs ou seulement des auteurs), il vaut mieux les synchroniser tous. Imaginez que votre code exécute le coeur artificiel d'une personne, vous ne voulez pas vraiment qu'il lise des valeurs erronées, et vous ne voulez certainement pas qu'une centrale électrique de votre ville fasse "boum" parce que quelqu'un a décidé de ne pas utiliser ce mutex. Épargnez-vous une nuit de sommeil lors d'une longue exécution, synchronisez-les.
Si vous n'avez qu'un seul thread qui lit, vous pouvez vous contenter d'un seul mutex, mais si vous prévoyez plusieurs lecteurs et plusieurs écrivains, vous aurez besoin d'un code sophistiqué pour le synchroniser. Je n'ai pas encore vu une bonne implémentation du verrouillage de lecture/écriture qui serait également "équitable".

5voto

NomeN Points 4106

Imaginez que vous êtes en train de lire la variable dans un thread, que ce thread est interrompu pendant la lecture et que la variable est modifiée par un thread en écriture. Maintenant, quelle est la valeur de l'entier lu après la reprise du fil de lecture ?

A moins que la lecture d'une variable ne soit une opération atomique, dans ce cas il suffit d'une seule instruction (d'assemblage), vous ne pouvez pas garantir que la situation ci-dessus ne puisse pas se produire. (La variable pourrait être écrite en mémoire, et récupérer la valeur prendrait plus d'une instruction).

Le consensus est que vous devriez encapsuler/bloquer toutes les écritures individuellement, tandis que les lectures peuvent être exécutées simultanément avec (seulement) d'autres lectures.

3voto

jalf Points 142628

Supposons que j'ai une variable entière dans une classe, et que cette variable peut être modifiée simultanément par d'autres threads. Les écritures sont protégées par un mutex. Dois-je également protéger les lectures ? J'ai entendu dire qu'il y a des architectures matérielles sur lesquelles, si un thread modifie une variable, et qu'un autre thread la lit, alors le résultat de la lecture sera un garbage ; dans ce cas, je dois protéger les lectures. Je n'ai jamais vu de telles architectures.

Dans le cas général, c'est potentiellement chaque architecture. Dans chaque architecture, il existe des cas où la lecture simultanée à l'écriture entraîne une perte de données. Cependant, presque toutes les architectures ont également des exceptions à cette règle.

Il est courant que les variables de la taille d'un mot soient lues et écrites de manière atomique, de sorte que la synchronisation n'est pas nécessaire lors de la lecture des données. ou l'écriture. La valeur appropriée sera écrite de manière atomique en tant qu'opération unique, et les threads liront le fichier actuel comme une seule opération atomique, même si un autre thread est en train d'écrire. Ainsi, pour les entiers, vous êtes en sécurité sur le plus architectures. Certains étendent cette garantie à quelques autres tailles également, mais cela dépend évidemment du matériel.

Pour les variables qui n'ont pas la taille d'un mot, la lecture et l'écriture seront généralement non atomiques, et devront être synchronisées par d'autres moyens.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X