12
votes

Atomic 64 Bit écrit avec GCC

Je me suis engagé dans un désordre confus concernant la programmation multithread et j'espérais que quelqu'un puisse venir et gifler une certaine compréhension en moi.

Après avoir fait un peu de lecture, je suis entendu dire que je devrais être capable de définir la valeur d'un ensemble 64 bits atomiquement sur un système 64 bits 1 .

J'ai trouvé beaucoup de cette lecture difficile cependant, alors pensais que je voudrais essayer de faire un test pour vérifier cela. J'ai donc écrit un programme simple avec un fil qui définirait une variable dans l'une des deux valeurs suivantes: xxx

et un autre fil qui vérifierait la valeur de foo : xxx

i réglez a = 1844674407370955161; et b = 1144644202170355111; . J'exécute ce programme et n'obtiens pas de sortie m'envêtant que bla n'est pas A ou B .

super, on dirait C'est probablement une écriture atomique ... mais j'ai alors changé le premier fil pour définir A et b directement, comme: xxx < / Pré>

Je re-exécuté et soudainement: xxx

Qu'est-ce qui a changé? De toute façon, j'en attribue un grand nombre à foo - le compilateur gère-t-il un nombre constant différemment, ou j'ai tout mal compris tout?

Merci!


1: Documentation Intel CPU, Section 8.1, Opérations atomiques garanties

2: liste de développement de la GCC discutant de ce GCC ne le garantit pas Dans la documentation, mais le noyau et d'autres programmes s'appuient sur celui-ci


5 commentaires

Avez-vous eu un avertissement lors de la compilation?


Je ne pense pas que ce soit le coupable, mais les littéraux ont du type INT par défaut, vous voudrez donc 1844674407370955161ull et 1144644202170355111Cull en tant que littéraux.


NIM, aucun avertissement lors de la compilation et -wall est défini


Etarion, je reçois un avertissement si ces chiffres sont à 1 chiffre de plus et doivent utiliser Ull pour vous débarrasser de l'avertissement. De toute façon, la même chose se produit.


Vous ne pouvez tout simplement pas traduire de manière fiable une garantie de la CPU en une garantie C / C ++, car vous ne savez pas ce que le compilateur fera.


3 Réponses :


3
votes

La documentation d'Intel CPU a raison, alignée 8 octets lues / écrit sont toujours atomiques sur du matériel récent (même sur des systèmes d'exploitation 32 bits).

Ce que vous ne nous disons pas, utilisez-vous un matériel 64 bits sur un système 32 bits? Si tel est le cas, l'écriture de 8 octets sera probablement divisée dans deux 4 octets écrit par le compilateur .

Jetez un coup d'œil à la section correspondante du code d'objet.


1 commentaires

Bonjour drhirsch, le système est de 64 bits Linux. Sortie Uname est: Linux ACORN 2.6.35-25-SERVER # 44 SMP VEN 11 FEV 11 15:50:10 GMT 2011 x86_64 GNU / Linux



12
votes

désassemblant la boucle, je reçois le code suivant avec gcc : xxx

donc il apparaît que gcc utilise-t-il à 32 -bit MOVL instruction avec des valeurs immédiates 32 bits. Il y a une instruction MOVQ qui peut déplacer un registre 64 bits en mémoire (ou la mémoire à un registre 64 bits), mais elle ne semble pas pouvoir définir déplacer une valeur immédiate à une mémoire. Adresse, le compilateur est donc forcé d'utiliser un registre temporaire, puis de déplacer la valeur en mémoire ou d'utiliser sur MOVL . Vous pouvez essayer de le forcer à utiliser un registre à l'aide d'une variable temporaire, mais cela peut ne pas fonctionner.

Références:


3 commentaires

Intéressant! Merci d'avoir pris le temps de démonter ça!


Quelles options de la version compilatrice, de la plate-forme et du compilateur utilisez-vous? Cela fait une énorme différence énorme. 64 bits écrit ne sera atomique que si l'objet est aligné sur 8 octets et que le système exécute 64 bits, le mode 32 bits (OS est 32 bits (OS est 32bit ou OS est 64, mais binaire est 32) Les écritures ne seront pas atomiques


GCC 4.2, MacOS X, CPU Core I7, OS est 64 bits, le code est compilé pour l'architecture X86_64. L'écriture de valeur de 64 bits est atomique, mais les valeurs immédiates de 64 bits ne peuvent pas être représentées en opcode sous forme de @aProgrammer pointant. Donc, le compilateur doit soit copier la valeur immédiate pour vous inscrire avant de la déplacer vers la mémoire, ou il doit stocker la valeur non copieuse de la moitié de la valeur immédiate de 32 bits.