1use crate::num::NonZero;
2use crate::sync::atomic::{Atomic, Ordering};
34/// A unique identifier for a running thread.
5///
6/// A `ThreadId` is an opaque object that uniquely identifies each thread
7/// created during the lifetime of a process. `ThreadId`s are guaranteed not to
8/// be reused, even when a thread terminates. `ThreadId`s are under the control
9/// of Rust's standard library and there may not be any relationship between
10/// `ThreadId` and the underlying platform's notion of a thread identifier --
11/// the two concepts cannot, therefore, be used interchangeably. A `ThreadId`
12/// can be retrieved from the [`id`] method on a [`Thread`].
13///
14/// # Examples
15///
16/// ```
17/// use std::thread;
18///
19/// let other_thread = thread::spawn(|| {
20/// thread::current().id()
21/// });
22///
23/// let other_thread_id = other_thread.join().unwrap();
24/// assert!(thread::current().id() != other_thread_id);
25/// ```
26///
27/// [`Thread`]: super::Thread
28/// [`id`]: super::Thread::id
29#[stable(feature = "thread_id", since = "1.19.0")]
30#[derive(#[automatically_derived]
#[stable(feature = "thread_id", since = "1.19.0")]
impl ::core::cmp::Eq for ThreadId {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<NonZero<u64>>;
}
}Eq, #[automatically_derived]
#[stable(feature = "thread_id", since = "1.19.0")]
impl ::core::marker::StructuralPartialEq for ThreadId { }
#[automatically_derived]
#[stable(feature = "thread_id", since = "1.19.0")]
impl ::core::cmp::PartialEq for ThreadId {
#[inline]
fn eq(&self, other: &ThreadId) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
#[doc(hidden)]
#[stable(feature = "thread_id", since = "1.19.0")]
unsafe impl ::core::clone::TrivialClone for ThreadId { }
#[automatically_derived]
#[stable(feature = "thread_id", since = "1.19.0")]
impl ::core::clone::Clone for ThreadId {
#[inline]
fn clone(&self) -> ThreadId {
let _: ::core::clone::AssertParamIsClone<NonZero<u64>>;
*self
}
}Clone, #[automatically_derived]
#[stable(feature = "thread_id", since = "1.19.0")]
impl ::core::marker::Copy for ThreadId { }Copy, #[automatically_derived]
#[stable(feature = "thread_id", since = "1.19.0")]
impl ::core::hash::Hash for ThreadId {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.0, state)
}
}Hash, #[automatically_derived]
#[stable(feature = "thread_id", since = "1.19.0")]
impl ::core::fmt::Debug for ThreadId {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "ThreadId",
&&self.0)
}
}Debug)]
31pub struct ThreadId(NonZero<u64>);
3233impl ThreadId {
34// Generate a new unique thread ID.
35pub(crate) fn new() -> ThreadId {
36#[cold]
37fn exhausted() -> ! {
38{
::core::panicking::panic_fmt(format_args!("failed to generate unique thread ID: bitspace exhausted"));
}panic!("failed to generate unique thread ID: bitspace exhausted")39 }
4041cfg_select! {
42 target_has_atomic = "64" => {
43use crate::sync::atomic::AtomicU64;
4445static COUNTER: Atomic<u64> = AtomicU64::new(0);
4647let mut last = COUNTER.load(Ordering::Relaxed);
48loop {
49let Some(id) = last.checked_add(1) else {
50exhausted();
51 };
5253match COUNTER.compare_exchange_weak(
54last,
55id,
56 Ordering::Relaxed,
57 Ordering::Relaxed,
58 ) {
59Ok(_) => return ThreadId(NonZero::new(id).unwrap()),
60Err(id) => last = id,
61 }
62 }
63 }
64_ => {
65use crate::cell::SyncUnsafeCell;
66use crate::hint::spin_loop;
67use crate::sync::atomic::AtomicBool;
68use crate::thread::yield_now;
6970// If we don't have a 64-bit atomic we use a small spinlock. We don't use Mutex
71 // here as we might be trying to get the current thread id in the global allocator,
72 // and on some platforms Mutex requires allocation.
73static COUNTER_LOCKED: Atomic<bool> = AtomicBool::new(false);
74static COUNTER: SyncUnsafeCell<u64> = SyncUnsafeCell::new(0);
7576// Acquire lock.
77let mut spin = 0;
78// Miri doesn't like it when we yield here as it interferes with deterministically
79 // scheduling threads, so avoid `compare_exchange_weak` to avoid spurious yields.
80while COUNTER_LOCKED.swap(true, Ordering::Acquire) {
81if spin <= 3 {
82for _ in 0..(1 << spin) {
83 spin_loop();
84 }
85 } else {
86 yield_now();
87 }
88 spin += 1;
89 }
90// This was `false` before the swap, so we got the lock.
9192 // SAFETY: we have an exclusive lock on the counter.
93unsafe {
94if let Some(id) = (*COUNTER.get()).checked_add(1) {
95*COUNTER.get() = id;
96 COUNTER_LOCKED.store(false, Ordering::Release);
97 ThreadId(NonZero::new(id).unwrap())
98 } else {
99 COUNTER_LOCKED.store(false, Ordering::Release);
100 exhausted()
101 }
102 }
103 }
104 }
105 }
106107#[cfg(any(not(target_thread_local), target_has_atomic = "64"))]
108pub(super) fn from_u64(v: u64) -> Option<ThreadId> {
109NonZero::new(v).map(ThreadId)
110 }
111112/// This returns a numeric identifier for the thread identified by this
113 /// `ThreadId`.
114 ///
115 /// As noted in the documentation for the type itself, it is essentially an
116 /// opaque ID, but is guaranteed to be unique for each thread. The returned
117 /// value is entirely opaque -- only equality testing is stable. Note that
118 /// it is not guaranteed which values new threads will return, and this may
119 /// change across Rust versions.
120#[must_use]
121 #[unstable(feature = "thread_id_value", issue = "67939")]
122pub fn as_u64(&self) -> NonZero<u64> {
123self.0
124}
125}