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?


  • Mod

    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^^


  • Mod

    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).


Log in to reply