summaryrefslogtreecommitdiffstats
path: root/Python/thread_nt.h
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2000-05-11 12:53:51 (GMT)
committerGuido van Rossum <guido@python.org>2000-05-11 12:53:51 (GMT)
commitede8c6eea1da425960b27ed735a41bc23a72a89a (patch)
tree4c5165a0d979e36c2b1d9eb53c018b7d1f9505d7 /Python/thread_nt.h
parent65e69002a2862cb3000610283b15954c208b7975 (diff)
downloadcpython-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/thread_nt.h')
-rw-r--r--Python/thread_nt.h25
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 ;