27 votes

Fonctions atomiques intégrées de gcc

http://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Atomic-Builtins.html

Je pense que le code suivant augmente la valeur de var de façon atomique.

volatile int var = 0;
__sync_fetch_and_add( &var, 1 )

J'ai compris que les codes ci-dessus étaient les suivants logique :

  1. Charger l'adresse de la variable var
  2. écrire le numéro 1 sur la variable var atomiquement - à travers le registre/cache, en quelque sorte

Cependant, je doute que ce qui suit soit aussi atomique

volatile int var = 0;
volatile int num = 1;
__sync_fetch_and_add( &var, num )

Puisqu'il peut être interprété comme

  1. Charger l'adresse de la variable var
  2. Charger la valeur de la variable num dans un registre
  3. écrire la valeur sur la variable var.

Après l'exécution du n°2, mais avant le n°3, le CPU/thread est interrompu et un autre CPU/thread met à jour la valeur de la variable num.

En d'autres termes, lorsque vous utilisez _ sync *() de gcc, puis-je utiliser une variable, et non une constante, comme second argument ?

Cela ne rompt-il pas l'atomicité ?

36voto

Dietrich Epp Points 72865

L'opération est en fait deux opérations.

__sync_fetch_and_add( &var, num )

Chargement num est atomique. En l'ajoutant à var est atomique. Mais deux opérations atomiques ne font pas une opération atomique lorsqu'elles sont mises ensemble. C'est pourquoi il est si difficile d'inventer de nouvelles structures de données sans verrou. En général, deux opérations thread-safe ne forment pas nécessairement une opération thread-safe lorsqu'elles sont composées. C'est la raison pour laquelle il est si difficile de réaliser des applications multithread correctes.

Vous voyez, __sync_fetch_and_add est en effet atomique, mais elle se comporte comme une fonction ordinaire -- elle prend donc la valeur actuelle de "num" comme paramètre. Il n'est pas tout à fait correct de dire que l'atomicité de la fonction est rompue -- parce que c'est la responsabilité de l'appelant de charger la valeur à partir de num et il ne fait pas partie de l'interface de la fonction. Je pourrais également me plaindre de cela :

__sync_fetch_and_add(&var, some_really_long_function());

Ou pire,

__sync_fetch_and_add(long_function_1(), long_function_2());

Vous dites qu'il "peut être interprété comme"

  1. Charger l'adresse de la variable var
  2. Charger la valeur de la variable num
  3. Effectuer l'addition atomique

Mais d'après la spécification C, ce n'est pas que mai être interprétée de cette façon, mais plutôt, elle debe être interprété de cette façon, sinon le compilateur ne serait pas conforme (en fait, il pourrait intervertir le #1 et le #2, mais ce n'est pas important ici).

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