From 4d04b0b0fe16dbf2227b308907bc2652be4c7c95 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 2 Jan 2020 04:02:48 +0100 Subject: [PATCH 1/2] Remove wrong advice about spin locks from `spin_loop_hint` docs Using a pure spin lock for a critical section in a preemptable thread is always wrong, however short the critical section may be. The thread might be preempted, which will cause all other threads to hammer busily at the core for the whole quant. Moreover, if threads have different priorities, this might lead to a priority inversion problem and a deadlock. More generally, a spinlock is not more efficient than a well-written mutex, which typically does several spin iterations at the start anyway. The advise about UP vs SMP is also irrelevant in the context of preemptive threads. --- src/libcore/sync/atomic.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index a2352c08e7316..ba41cd2b7a08e 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -134,16 +134,8 @@ use crate::hint::spin_loop; /// This function is different from [`std::thread::yield_now`] which directly yields to the /// system's scheduler, whereas `spin_loop_hint` does not interact with the operating system. /// -/// Spin locks can be very efficient for short lock durations because they do not involve context -/// switches or interaction with the operating system. For long lock durations they become wasteful -/// however because they use CPU cycles for the entire lock duration, and using a -/// [`std::sync::Mutex`] is likely the better approach. If actively spinning for a long time is -/// required, e.g. because code polls a non-blocking API, calling [`std::thread::yield_now`] -/// or [`std::thread::sleep`] may be the best option. -/// -/// **Note**: Spin locks are based on the underlying assumption that another thread will release -/// the lock 'soon'. In order for this to work, that other thread must run on a different CPU or -/// core (at least potentially). Spin locks do not work efficiently on single CPU / core platforms. +/// If actively spinning for a long time is required, e.g. because code polls a non-blocking API, +/// calling [`std::thread::yield_now`] or [`std::thread::sleep`] may be the best option. /// /// **Note**: On platforms that do not support receiving spin-loop hints this function does not /// do anything at all. From b25eeef88d55a412c0e0bec7c0989d5a7969f195 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 5 Jan 2020 20:06:52 +0100 Subject: [PATCH 2/2] Add more nuanced advice about spin_loop_hint --- src/libcore/sync/atomic.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index ba41cd2b7a08e..fae95ca5cdb36 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -134,8 +134,10 @@ use crate::hint::spin_loop; /// This function is different from [`std::thread::yield_now`] which directly yields to the /// system's scheduler, whereas `spin_loop_hint` does not interact with the operating system. /// -/// If actively spinning for a long time is required, e.g. because code polls a non-blocking API, -/// calling [`std::thread::yield_now`] or [`std::thread::sleep`] may be the best option. +/// A common use case for `spin_loop_hint` is implementing bounded optimistic spinning in a CAS +/// loop in synchronization primitives. To avoid problems like priority inversion, it is strongly +/// recommended that the spin loop is terminated after a finite amount of iterations and an +/// appropriate blocking syscall is made. /// /// **Note**: On platforms that do not support receiving spin-loop hints this function does not /// do anything at all.