cmpxchg hab ich was falsch verstanden?
-
hallöle
Bin beim Assembler lernen auf den cmpxchg Befehl gestoßen und hab mir dazu das folgende programm geschrieben (Achtung GNU Assembler):
.section .data value: .int 23 output: .ascii "EAX:\t%0#10x\n" .ascii "EBX:\t%0#10x\n" .asciz "Value:\t%0#10x\n\n" .section .text .globl main main: // for gdb nop // Load Values movl $23787332, %ebx movl $23, %eax // Show involved r/m pushl value pushl %ebx pushl %eax pushl $output call printf addl $16, %esp // for gdb breakhere: // compare and exchange cmpxchg %ebx, value // Show involved r/m pushl value pushl %ebx pushl %eax pushl $output call printf addl $16, %esp pushl $0 call exit
So wie ich das verstanden habe, wird der zweite Operand mit dem EAX-register verglichen und wenn der Wert gleich ist, so wird der wert des ersten operands in den zweiten geladen, wenn nicht, so wird der Wert des zweiten operands in das eax-register geladen. nun in diesem Fall sind eax und der wert gleich, ich bekomm allerdings die folgende ausgabe:
azra@AzraPC:~/Projects/asm$ ./cmpxchgtest EAX: 0x00000017 EBX: 0x016af744 Value: 0x00000017 EAX: 0x00000017 EBX: 0x016af744 Value: 0x00000017
hab auch beim debuggen nocheinmal festgestellt, dass sich der Wert bei "value" nicht ändert. hab ich etwas falsch verstanden?
-
Azrael, il Meraz schrieb:
hab ich etwas falsch verstanden?
Je nach ABI kann sich der Wert von einigen Registern beim Aufruf von C-Funktionen ändern - eax,ecx,edx sind typischerweise davon betroffen. Ich würde also annehmen, dass der Inhalt von eax unmittelbar nach dem Aufruf von printf nicht mehr 0x17 ist.
-
ah. danke. tatsächlich - ein movl $23, %eax nach der Ausgabe lässt das Programm richtig funktionieren...
-
Noch eine frage: Wo findet man den Einsatz dieser Anweisung häufiger?
Kann es sein, dass es was mit Multithreading zu tun hat?
-
ja, das ist eine funktion die garantiert atomar abzulaufen. wuerdest du das selbst in mehreren instruktionen machen, koennte es sein dass nach deinem vergleich von eax und value ein anderer thread den value aendert und du ueberschreibst den wert kurz darauf. es ist also nicht atomar und wenn sich beide threads darauf verlassen dass ihr wert drinn steht, dem aber nicht so ist, gibt es vermutlich fehler
der befehl wird oft verwendet um einem thread garantierten besitzt von etwas zu geben, indem er derjenige ist der diese variable gesetzt hat. ein anderer thread kann dann den waert nicht aendern und kann dann z.b. loopen bis er erfolgreich die variable aendert, weil dann der 'owner' thread die variable wieder auf 0 gesetzt hat.
dieser 'lock' kann fuer allerlei resourcen gemacht werden z.b. bereiche im ram, festplattenzugriffe etc.
-
thx
also, wenn ich des richtig verstanden habe, "lock"t der Befehl automatisch die speicherstelle für einen thread (also lässt nur einen daraf zugrefen)? hmm... Wird mal zeit, sich tiefgehender mit Multithreading zu beschäftigen
-
Azrael, il Meraz schrieb:
thx
also, wenn ich des richtig verstanden habe, "lock"t der Befehl automatisch die speicherstelle für einen thread (also lässt nur einen daraf zugrefen)? hmm... Wird mal zeit, sich tiefgehender mit Multithreading zu beschäftigen
nein, du kannst aber mit dem befehl einen lock implementieren, weil nur ein einziger thread den wert 0 durch einen anderen ersetzen kann, bei allen anderen threads "so wird der Wert des zweiten operands in das eax-register geladen. "
wuerdest du den befehl selbst implementieren wuerde er in etwa nach
cmp value,0 je m1 mov eax, value jmp m2 m1: mov value, ebx m2:
aussehen.
wenn nun nach dem
cmp value,0
ein anderer thread etwas in value schreibt um quasi seinen besitzt ueber die variable (und die damit verbundenen resourcen) zu signalisieren, wurdest du das nicht mitbekommen, sondern mit
move value, ebx
ueberschreiben und dein thread wuerde 'denken' er besitzt die resource.
deswegen gibt es einen befehl dafuer, er macht alles auf einmal und garantiert dass diese 'race condition' bei multithreading nicht auftritt.
-
oha. danke nochmals. mal wieder was dazugelernt^^
-
Um deutlicher zu sein, CMPXCHG (und die Verwandten CMPXCHG8B und CMPXCHG16B) sind dann und nur dann atomar, wenn explizit das lock Präfix benutzt wird (impliziert Memorybarrier).