diff options
| author | bors <bors@rust-lang.org> | 2016-10-10 04:04:51 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-10-10 04:04:51 -0700 |
| commit | 6d620843f62b6cf3182528ffcaa877eba461bfbb (patch) | |
| tree | 0556b5246e14a08e21735c1942854b23b7c819c6 /src/libstd | |
| parent | a7bfb1aba9d089a0464c03b3841e889c6ee7c4f1 (diff) | |
| parent | 032bffa5b8ae6c3977884c4e10fd6ab6a5dc5ef6 (diff) | |
| download | rust-6d620843f62b6cf3182528ffcaa877eba461bfbb.tar.gz rust-6d620843f62b6cf3182528ffcaa877eba461bfbb.zip | |
Auto merge of #36341 - sagebind:thread_id, r=alexcrichton
Add ThreadId for comparing threads This adds the capability to store and compare threads with the current calling thread via a new struct, `std::thread::ThreadId`. Addresses the need outlined in issue #21507. This avoids the need to add any special checks to the existing thread structs and does not rely on the system to provide an identifier for a thread, since it seems that this approach is unreliable and undesirable. Instead, this simply uses a lazily-created, thread-local `usize` whose value is copied from a global atomic counter. The code should be simple enough that it should be as much reliable as the `#[thread_local]` attribute it uses (however much that is). `ThreadId`s can be compared directly for equality and have copy semantics. Also see these other attempts: - rust-lang/rust#29457 - rust-lang/rust#29448 - rust-lang/rust#29447 And this in the RFC repo: rust-lang/rfcs#1435
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/thread/mod.rs | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 901ff98fcb3..150482e4af4 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -166,6 +166,7 @@ use panicking; use str; use sync::{Mutex, Condvar, Arc}; use sys::thread as imp; +use sys_common::mutex; use sys_common::thread_info; use sys_common::util; use sys_common::{AsInner, IntoInner}; @@ -525,12 +526,52 @@ pub fn park_timeout(dur: Duration) { } //////////////////////////////////////////////////////////////////////////////// +// ThreadId +//////////////////////////////////////////////////////////////////////////////// + +/// A unique identifier for a running thread. +/// +/// A `ThreadId` is an opaque object that has a unique value for each thread +/// that creates one. `ThreadId`s do not correspond to a thread's system- +/// designated identifier. +#[unstable(feature = "thread_id", issue = "21507")] +#[derive(Eq, PartialEq, Copy, Clone)] +pub struct ThreadId(u64); + +impl ThreadId { + // Generate a new unique thread ID. + fn new() -> ThreadId { + static GUARD: mutex::Mutex = mutex::Mutex::new(); + static mut COUNTER: u64 = 0; + + unsafe { + GUARD.lock(); + + // If we somehow use up all our bits, panic so that we're not + // covering up subtle bugs of IDs being reused. + if COUNTER == ::u64::MAX { + GUARD.unlock(); + panic!("failed to generate unique thread ID: bitspace exhausted"); + } + + let id = COUNTER; + COUNTER += 1; + + GUARD.unlock(); + + ThreadId(id) + } + } +} + +//////////////////////////////////////////////////////////////////////////////// // Thread //////////////////////////////////////////////////////////////////////////////// /// The internal representation of a `Thread` handle struct Inner { name: Option<CString>, // Guaranteed to be UTF-8 + id: ThreadId, lock: Mutex<bool>, // true when there is a buffered unpark cvar: Condvar, } @@ -551,6 +592,7 @@ impl Thread { Thread { inner: Arc::new(Inner { name: cname, + id: ThreadId::new(), lock: Mutex::new(false), cvar: Condvar::new(), }) @@ -569,6 +611,12 @@ impl Thread { } } + /// Gets the thread's unique identifier. + #[unstable(feature = "thread_id", issue = "21507")] + pub fn id(&self) -> ThreadId { + self.inner.id + } + /// Gets the thread's name. /// /// # Examples @@ -977,6 +1025,17 @@ mod tests { thread::sleep(Duration::from_millis(2)); } + #[test] + fn test_thread_id_equal() { + assert!(thread::current().id() == thread::current().id()); + } + + #[test] + fn test_thread_id_not_equal() { + let spawned_id = thread::spawn(|| thread::current().id()).join().unwrap(); + assert!(thread::current().id() != spawned_id); + } + // NOTE: the corresponding test for stderr is in run-pass/thread-stderr, due // to the test harness apparently interfering with stderr configuration. } |
