From ede8c6eea1da425960b27ed735a41bc23a72a89a Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Thu, 11 May 2000 12:53:51 +0000 Subject: Bill Tutt: Calling Sleep(0) for a spinlock can cause a priority inversion, adding comments to explain what's going on. --- Python/thread_nt.h | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Python/thread_nt.h b/Python/thread_nt.h index 0c7ced4..c8ed6cd 100644 --- a/Python/thread_nt.h +++ b/Python/thread_nt.h @@ -50,9 +50,32 @@ static PVOID WINAPI interlocked_cmp_xchg(PVOID *dest, PVOID exc, PVOID comperand { static LONG spinlock = 0 ; PVOID result ; + DWORD dwSleep = 0; /* Acqire spinlock (yielding control to other threads if cant aquire for the moment) */ - while(InterlockedExchange(&spinlock, 1)) Sleep(0) ; + while(InterlockedExchange(&spinlock, 1)) + { + // Using Sleep(0) can cause a priority inversion. + // Sleep(0) only yields the processor if there's + // another thread of the same priority that's + // ready to run. If a high-priority thread is + // trying to acquire the lock, which is held by + // a low-priority thread, then the low-priority + // thread may never get scheduled and hence never + // free the lock. NT attempts to avoid priority + // inversions by temporarily boosting the priority + // of low-priority runnable threads, but the problem + // can still occur if there's a medium-priority + // thread that's always runnable. If Sleep(1) is used, + // then the thread unconditionally yields the CPU. We + // only do this for the second and subsequent even + // iterations, since a millisecond is a long time to wait + // if the thread can be scheduled in again sooner + // (~100,000 instructions). + // Avoid priority inversion: 0, 1, 0, 1,... + Sleep(dwSleep); + dwSleep = !dwSleep; + } result = *dest ; if (result == comperand) *dest = exc ; -- cgit v0.12