Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ede8c6e

Browse files
committed
Bill Tutt:
Calling Sleep(0) for a spinlock can cause a priority inversion, adding comments to explain what's going on.
1 parent 65e6900 commit ede8c6e

1 file changed

Lines changed: 24 additions & 1 deletion

File tree

Python/thread_nt.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,32 @@ static PVOID WINAPI interlocked_cmp_xchg(PVOID *dest, PVOID exc, PVOID comperand
5050
{
5151
static LONG spinlock = 0 ;
5252
PVOID result ;
53+
DWORD dwSleep = 0;
5354

5455
/* Acqire spinlock (yielding control to other threads if cant aquire for the moment) */
55-
while(InterlockedExchange(&spinlock, 1)) Sleep(0) ;
56+
while(InterlockedExchange(&spinlock, 1))
57+
{
58+
// Using Sleep(0) can cause a priority inversion.
59+
// Sleep(0) only yields the processor if there's
60+
// another thread of the same priority that's
61+
// ready to run. If a high-priority thread is
62+
// trying to acquire the lock, which is held by
63+
// a low-priority thread, then the low-priority
64+
// thread may never get scheduled and hence never
65+
// free the lock. NT attempts to avoid priority
66+
// inversions by temporarily boosting the priority
67+
// of low-priority runnable threads, but the problem
68+
// can still occur if there's a medium-priority
69+
// thread that's always runnable. If Sleep(1) is used,
70+
// then the thread unconditionally yields the CPU. We
71+
// only do this for the second and subsequent even
72+
// iterations, since a millisecond is a long time to wait
73+
// if the thread can be scheduled in again sooner
74+
// (~100,000 instructions).
75+
// Avoid priority inversion: 0, 1, 0, 1,...
76+
Sleep(dwSleep);
77+
dwSleep = !dwSleep;
78+
}
5679
result = *dest ;
5780
if (result == comperand)
5881
*dest = exc ;

0 commit comments

Comments
 (0)