#![allow(clippy::disallowed_names, clippy::mutex_atomic)]
#![cfg(feature = "thread_safe")]
use rand::Rng;
use shaku::{module, Component, HasComponent, Interface};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
trait Foo: Interface {
fn get_value(&self) -> usize;
fn set_value(&self, _: usize);
}
#[derive(Component)]
#[shaku(interface = Foo)]
struct FooImpl {
#[shaku(default = AtomicUsize::new(FOO_DEFAULT_VALUE))]
value: AtomicUsize,
}
impl Foo for FooImpl {
fn get_value(&self) -> usize {
self.value.load(Ordering::SeqCst)
}
fn set_value(&self, val: usize) {
self.value.store(val, Ordering::SeqCst)
}
}
module! {
FooModule {
components = [FooImpl],
providers = []
}
}
const FOO_DEFAULT_VALUE: usize = 17;
const NB_THREADS: usize = 10;
const MAX_SLEEP_TIME: u64 = 2000;
#[test]
fn simple_multithreaded_resolve_ref() {
let module = FooModule::builder().build();
let shared_module = Arc::new(module);
let mut handles = Vec::new();
for i in 0..NB_THREADS {
let shared_module = Arc::clone(&shared_module);
handles.push(
thread::Builder::new()
.name(format!("reader #{}", &i))
.spawn(move || {
let sleep_ms = rand::thread_rng().gen_range(0..MAX_SLEEP_TIME);
thread::sleep(Duration::from_millis(sleep_ms));
let foo: &dyn Foo = shared_module.resolve_ref();
assert_eq!(foo.get_value(), FOO_DEFAULT_VALUE);
})
.unwrap(),
);
}
for handle in handles {
handle.join().unwrap();
}
}
#[test]
fn simple_multithreaded_resolve_ref_n_mut() {
let module = FooModule::builder().build();
let shared_module = Arc::new(module);
let latest_data: Arc<Mutex<usize>> = Arc::new(Mutex::new(FOO_DEFAULT_VALUE));
let mut handles = Vec::new();
for i in 0..NB_THREADS {
let (shared_module, latest_data) = (shared_module.clone(), latest_data.clone());
handles.push(
thread::Builder::new()
.name(format!("reader #{}", &i))
.spawn(move || {
let handle = thread::current();
let sleep_ms = rand::thread_rng().gen_range(0..MAX_SLEEP_TIME);
thread::sleep(Duration::from_millis(sleep_ms));
let use_mut = rand::thread_rng().gen_bool(0.5);
if use_mut {
let foo: &dyn Foo = shared_module.resolve_ref();
let new_value: usize = rand::thread_rng().gen_range(0..256);
foo.set_value(new_value);
assert_eq!(foo.get_value(), new_value);
let mut latest_data_lock = latest_data.lock().unwrap();
*latest_data_lock = new_value;
println!(
"In thread {:?} > resolve ok > value changed to {}",
&handle.name().unwrap(),
new_value
);
} else {
let foo: &dyn Foo = shared_module.resolve_ref();
let latest_data_lock = latest_data.lock().unwrap();
let data = *latest_data_lock;
println!(
"In thread {:?} > resolve ok > value should be {}",
&handle.name().unwrap(),
data
);
assert_eq!(foo.get_value(), data);
}
})
.unwrap(),
);
}
for handle in handles {
handle.join().unwrap();
}
}