Struct SharedThread

Source
pub struct SharedThread<T> { /* private fields */ }
Expand description

A wrapper around std::thread::JoinHandle that allows for multiple waiters.

The high-level differences between SharedThread and JoinHandle are:

  • join takes &self rather than &mut self.
  • join returns &T rather than T. For taking ownership of T, see into_output.
  • SharedThread provides try_join.
  • Rather than converting panics in into std::thread::Result, which usually requires the caller to .unwrap() every .join(), SharedThread propagates panics automatically.

§Example

use shared_thread::SharedThread;
use std::sync::atomic::{AtomicBool, Ordering::Relaxed};

// Use this flag to tell our shared thread when to stop.
static EXIT_FLAG: AtomicBool = AtomicBool::new(false);

// Start a background thread that we'll share with several waiting threads.
let shared_thread = SharedThread::spawn(|| {
    // Pretend this is some expensive, useful background work...
    while (!EXIT_FLAG.load(Relaxed)) {}

    42
});

// How to share a SharedThread object with other threads is up to you. In this sense it's like
// any other object you might need to share, like say a HashMap or a File. The common options
// are to put it in an Arc, or to let "scoped" threads borrow it directly. Let's use scoped
// threads.
std::thread::scope(|scope| {
    // Spawn three waiter threads that each wait on the shared thread.
    let waiter1 = scope.spawn(|| shared_thread.join());
    let waiter2 = scope.spawn(|| shared_thread.join());
    let waiter3 = scope.spawn(|| shared_thread.join());

    // In this example, the shared thread is going to keep looping until we set the EXIT_FLAG.
    // In the meantime, .is_finished() returns false, and .try_join() returns None.
    assert!(!shared_thread.is_finished());
    assert_eq!(shared_thread.try_join(), None);

    // Ask the shared thread to stop looping.
    EXIT_FLAG.store(true, Relaxed);

    // At this point the calls to .join() above will return quickly, and each of the waiter
    // threads will get a reference to the shared thread's output, &42.
    assert_eq!(*waiter1.join().unwrap(), 42);
    assert_eq!(*waiter2.join().unwrap(), 42);
    assert_eq!(*waiter3.join().unwrap(), 42);

    // Now that the shared thread has finished, .is_finished() returns true, and .try_join()
    // returns Some(&42).
    assert!(shared_thread.is_finished());
    assert_eq!(*shared_thread.try_join().unwrap(), 42);
});

 // We can take ownership of the output by consuming the SharedThread object. As with any
 // non-Copy type in Rust, this requires that the SharedThread is not borrowed.
 assert_eq!(shared_thread.into_output(), 42);

Implementations§

Source§

impl<T: Send + 'static> SharedThread<T>

Source

pub fn spawn<F>(f: F) -> Self
where F: FnOnce() -> T + Send + 'static,

Spawn a new SharedThread.

§Panics

This function calls std::thread::spawn internally, which panics if it fails to spawn a thread.

Source§

impl<T> SharedThread<T>

Source

pub fn new(handle: JoinHandle<T>) -> Self

Wrap an existing JoinHandle.

This is equivalent to SharedThread::from.

Source

pub fn try_join(&self) -> Option<&T>

Return Some(&T) if the shared thread has already finished, otherwise None. This never blocks.

§Panics

This function panics if the shared thread panicked.

Source

pub fn join(&self) -> &T

Wait for the shared thread to finish, then return &T. This blocks the current thread until the shared thread is finished.

§Panics

This function panics if the shared thread panicked.

Source

pub fn into_output(self) -> T

Wait for the shared thread to finish, then return T. This blocks the current thread until the shared thread is finished. This requires ownership of the SharedThread and consumes it.

§Panics

This function panics if the shared thread panicked.

Source

pub fn is_finished(&self) -> bool

Return true if the shared thread has finished, false otherwise.

This function never blocks. If it returns true, try_join is guaranteed to return Some(T), and join is guaranteed to return quickly.

§Panics

This function may panic if the shared thread panicked. Currently it only panics if another method has already panicked, but this is not guaranteed.

Trait Implementations§

Source§

impl<T: Debug> Debug for SharedThread<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T> From<JoinHandle<T>> for SharedThread<T>

Source§

fn from(handle: JoinHandle<T>) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl<T> !Freeze for SharedThread<T>

§

impl<T> RefUnwindSafe for SharedThread<T>

§

impl<T> Send for SharedThread<T>
where T: Send,

§

impl<T> Sync for SharedThread<T>
where T: Sync + Send,

§

impl<T> Unpin for SharedThread<T>
where T: Unpin,

§

impl<T> UnwindSafe for SharedThread<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.