#threading #container #thread-unsafe

thread-safe

Container that allows thread safety for thread-unsafe objects

3 releases

0.1.2 Aug 21, 2021
0.1.1 Jul 2, 2021
0.1.0 Jun 19, 2021

#1068 in Concurrency

MIT/Apache

16KB
242 lines

thread-safe

This crate implements a simple container that allows thread-unsafe variables to be sent across threads, as long as they are only directly accessed from the origin thread. This crate allows for breadthread to not have any unsafe code in it.

License

This crate is dual-licensed under the MIT and Apache 2.0 Licenses, just like Rust proper is.


lib.rs:

Let's say you have some thread-unsafe data. For whatever reason, it can't be used outside of the thread it originated in. This thread-unsafe data is a component of a larger data struct that does need to be sent around between other threads.

The ThreadSafe contains data that can only be utilized in the thread it was created in. When a reference is attempted to be acquired to the interior data, it checks for the current thread it comes from.

ThreadKey

The ThreadKey is a wrapper around ThreadId, but !Send. This allows one to certify that the current thread has the given ThreadId, without having to go through thread::current().id().

Example

use std::{cell::Cell, sync::{Arc, atomic}, thread};
use thread_safe::ThreadSafe;

#[derive(Debug)]
struct InnerData {
    counter: atomic::AtomicUsize,
    other_counter: ThreadSafe<Cell<usize>>,
}

fn increment_data(data: &InnerData) {
    data.counter.fetch_add(1, atomic::Ordering::SeqCst);
    if let Ok(counter) = data.other_counter.try_get_ref() {
        counter.set(counter.get() + 1);
    }
}

let data = Arc::new(InnerData {
    counter: atomic::AtomicUsize::new(0),
    other_counter: ThreadSafe::new(Cell::new(0)),
});

let mut handles = vec![];

for _ in 0..10 {
    let data = data.clone();
    handles.push(thread::spawn(move || increment_data(&data)));
}

increment_data(&data);

for handle in handles {
    handle.join().unwrap();
}

let data = Arc::try_unwrap(data).unwrap();
assert_eq!(data.counter.load(atomic::Ordering::Relaxed), 11);
assert_eq!(data.other_counter.get_ref().get(), 1);

No runtime deps