Gestern habe ich this question auf, wie man einen schnellen Spinlock geschrieben. Dank Cory Nelson habe ich anscheinend eine Methode gefunden, die die anderen in meiner Frage besprochenen Methoden übertrifft. Ich benutze die CMPXCHG
Anweisung, um zu überprüfen, ob die Sperre 0 und damit frei ist. CMPXCHG
arbeitet auf "BYTE", WORD
und DWORD
. Ich würde annehmen, dass der Befehl schneller auf BYTE
funktionieren würde. Aber ich schrieb eine Sperre jeden des Datentypen Implementierung:cmpxchg für WORD schneller als für BYTE
inline void spin_lock_8(char* lck)
{
__asm
{
mov ebx, lck ;move lck pointer into ebx
xor cl, cl ;set CL to 0
inc cl ;increment CL to 1
pause ;
spin_loop:
xor al, al ;set AL to 0
lock cmpxchg byte ptr [ebx], cl ;compare AL to CL. If equal ZF is set and CL is loaded into address pointed to by ebx
jnz spin_loop ;jump to spin_loop if ZF
}
}
inline void spin_lock_16(short* lck)
{
__asm
{
mov ebx, lck
xor cx, cx
inc cx
pause
spin_loop:
xor ax, ax
lock cmpxchg word ptr [ebx], cx
jnz spin_loop
}
}
inline void spin_lock_32(int* lck)
{
__asm
{
mov ebx, lck
xor ecx, ecx
inc ecx
pause
spin_loop:
xor eax, eax
lock cmpxchg dword ptr [ebx], ecx
jnz spin_loop
}
}
inline spin_unlock(<anyType>* lck)
{
__asm
{
mov ebx, lck
mov <byte/word/dword> ptr [ebx], 0
}
}
Das Schloss wurde dann den folgenden Pseudo-Code getestet mit (bitte beachten Sie, dass die LCM-Zeiger immer auf eine Adresse teilbaren von 4 Punkt):
Ich habe die folgenden Ergebnisse in msecs auf einem Prozessor mit 2 physischen Kernen in der Lage, 4 Threads (Ivy Bridge) laufen gemessen.
1 thread 2 threads 4 threads
8-bit 200 700 3200
16-bit 200 500 1400
32-bit 200 900 3400
Die Daten legen nahe, dass alle Funktionen die gleiche Zeit benötigen, um ausgeführt zu werden. Aber wenn mehrere Threads prüfen müssen, ob lck == 0
mit einem 16-Bit deutlich schneller sein kann. Warum das? Ich nehme an, es hat etwas mit der Ausrichtung der lck
zu tun?
Vielen Dank im Voraus.
'Ich weiß, das ist kein großer Unterschied, aber als Spinlock ist ein stark genutztes Objekt' - Port habe in mehr als 30 Jahren Multithread-Softwareentwicklung keinen einzigen mehr verwendet. –
Versuchen Sie, die "Pause" -Anweisung INNERHALB der Spin-Schleife und nicht außerhalb der Schleife zu bewegen. 16-Bit-Anweisungen erfordern zusätzliche 0x66/0x67-Präfix-Bytes, die sie etwas größer/langsamer als 8- oder 32-Bit-Befehle machen. Es kann also sein, dass der zusätzliche Overhead die Schleife verlangsamt, um Konflikte im 16-Bit-Fall zu reduzieren. –
Ich würde nicht überrascht sein, wenn diese Sperren zu zufälliger Beschädigung führen, da sie ebx (ein aufgerufenes Speicherregister) ändern, ohne sie zu speichern und wiederherzustellen, was einen Wert, den ein Aufrufer zu erhalten erwartet, beschädigt. Verwenden Sie stattdessen edx. –