diff options
author | Guido van Rossum <guido@python.org> | 2000-05-11 12:53:51 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 2000-05-11 12:53:51 (GMT) |
commit | ede8c6eea1da425960b27ed735a41bc23a72a89a (patch) | |
tree | 4c5165a0d979e36c2b1d9eb53c018b7d1f9505d7 /Python | |
parent | 65e69002a2862cb3000610283b15954c208b7975 (diff) | |
download | cpython-ede8c6eea1da425960b27ed735a41bc23a72a89a.zip cpython-ede8c6eea1da425960b27ed735a41bc23a72a89a.tar.gz cpython-ede8c6eea1da425960b27ed735a41bc23a72a89a.tar.bz2 |
Bill Tutt:
Calling Sleep(0) for a spinlock can cause a priority inversion, adding
comments to explain what's going on.
Diffstat (limited to 'Python')
-rw-r--r-- | Python/thread_nt.h | 25 |
1 files changed, 24 insertions, 1 deletions
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 ; |