Sometimes we have two fields we want to access with a Mutex. Instead of putting a Mutex around each field, we can combine the 2 fields and use 1 Mutex.
use std::sync::*;
use std::thread;
use std::time::*;
const MAX: usize = 1000000;
const THREADS: usize = 8;
struct Test1 {
vals1: Mutex<Vec<usize>>,
vals2: Mutex<Vec<usize>>,
}
struct Test2 {
vals: Mutex<(Vec<usize>, Vec<usize>)>,
}
fn main() {
// Version 1: use 2 separate Mutexes.
let t0 = Instant::now();
let arc = Arc::new(Test1 {
vals1: Mutex::new(vec![]),
vals2: Mutex::new(vec![]),
});
let mut thread_vec = vec![];
for _ in 0..THREADS {
thread_vec.push(arc.clone());
}
let mut children = vec![];
for t in thread_vec {
children.push(thread::spawn(move || {
for _ in 0..MAX {
let mut vals1 = t.vals1.lock().unwrap();
vals1.push(0);
let mut vals2 = t.vals2.lock().unwrap();
vals2.push(0);
}
}));
}
for child in children {
let _ = child.join();
}
println!(
"{}", t0.elapsed().as_nanos());
// Version 2: use 1 Mutex with 2 separate values in it.
let t1 = Instant::now();
let arc = Arc::new(Test2 {
vals: Mutex::new((vec![], vec![])),
});
let mut thread_vec = vec![];
for _ in 0..THREADS {
thread_vec.push(arc.clone());
}
let mut children = vec![];
for t in thread_vec {
children.push(thread::spawn(move || {
for _ in 0..MAX {
let mut vals = t.vals.lock().unwrap();
vals.0.push(0);
vals.1.push(0);
}
}));
}
for child in children {
let _ = child.join();
}
println!(
"{}", t1.elapsed().as_nanos());
}
1663781334 ns lock(), push(), lock(), push()
1334830000 ns lock(), push(), push()