11#![ stable( feature = "core_hint" , since = "1.27.0" ) ]
22
33//! Hints to compiler that affects how code should be emitted or optimized.
4+ //! Hints may be compile time or runtime.
45
56use crate :: intrinsics;
67
@@ -24,7 +25,6 @@ use crate::intrinsics;
2425/// Otherwise, consider using the [`unreachable!`] macro, which does not allow
2526/// optimizations but will panic when executed.
2627///
27- ///
2828/// # Example
2929///
3030/// ```
@@ -51,18 +51,62 @@ pub const unsafe fn unreachable_unchecked() -> ! {
5151 unsafe { intrinsics:: unreachable ( ) }
5252}
5353
54- /// Emits a machine instruction hinting to the processor that it is running in busy-wait
55- /// spin-loop ("spin lock").
54+ /// Emits a machine instruction to signal the processor that it is running in
55+ /// a busy-wait spin-loop ("spin lock").
56+ ///
57+ /// Upon receiving the spin-loop signal the processor can optimize its behavior by,
58+ /// for example, saving power or switching hyper-threads.
59+ ///
60+ /// This function is different from [`thread::yield_now`] which directly
61+ /// yields to the system's scheduler, whereas `spin_loop` does not interact
62+ /// with the operating system.
63+ ///
64+ /// A common use case for `spin_loop` is implementing bounded optimistic
65+ /// spinning in a CAS loop in synchronization primitives. To avoid problems
66+ /// like priority inversion, it is strongly recommended that the spin loop is
67+ /// terminated after a finite amount of iterations and an appropriate blocking
68+ /// syscall is made.
69+ ///
70+ /// **Note**: On platforms that do not support receiving spin-loop hints this
71+ /// function does not do anything at all.
72+ ///
73+ /// # Examples
5674///
57- /// For a discussion of different locking strategies and their trade-offs, see
58- /// [`core::sync::atomic::spin_loop_hint`].
75+ /// ```
76+ /// use std::sync::atomic::{AtomicBool, Ordering};
77+ /// use std::sync::Arc;
78+ /// use std::{hint, thread};
79+ ///
80+ /// // A shared atomic value that threads will use to coordinate
81+ /// let live = Arc::new(AtomicBool::new(false));
82+ ///
83+ /// // In a background thread we'll eventually set the value
84+ /// let bg_work = {
85+ /// let live = live.clone();
86+ /// thread::spawn(move || {
87+ /// // Do some work, then make the value live
88+ /// do_some_work();
89+ /// live.store(true, Ordering::Release);
90+ /// })
91+ /// };
5992///
60- /// **Note**: On platforms that do not support receiving spin-loop hints this function does not
61- /// do anything at all.
93+ /// // Back on our current thread, we wait for the value to be set
94+ /// while live.load(Ordering::Acquire) {
95+ /// // The spin loop is a hint to the CPU that we're waiting, but probably
96+ /// // not for very long
97+ /// hint::spin_loop();
98+ /// }
99+ ///
100+ /// // The value is now set
101+ /// # fn do_some_work() {}
102+ /// do_some_work();
103+ /// bg_work.join()?;
104+ /// # Ok::<(), Box<dyn core::any::Any + Send + 'static>>(())
105+ /// ```
62106///
63- /// [`core::sync::atomic::spin_loop_hint `]: crate::sync::atomic::spin_loop_hint
107+ /// [`thread::yield_now `]: ../../std/thread/fn.yield_now.html
64108#[ inline]
65- #[ unstable ( feature = "renamed_spin_loop" , issue = "55002 " ) ]
109+ #[ stable ( feature = "renamed_spin_loop" , since = "1.49.0 " ) ]
66110pub fn spin_loop ( ) {
67111 #[ cfg( all( any( target_arch = "x86" , target_arch = "x86_64" ) , target_feature = "sse2" ) ) ]
68112 {
0 commit comments