One of the things that Rust promises to protect you against is data races, namely, when data is being modified from one thread in parallel with another thread using that data. That's pretty much exactly what you are trying to do here.
One way to do this is to use a Mutex
. A Mutex
works by introducing a lock
method for accessing your data. Whenever you call lock
, the mutex will wait until nobody else is accessing the data, and then give you exclusive access to the data. Once the lock
goes out of scope, the lock is released and some other call to lock
will be given access, if any. That looks like this:
use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use std::thread;
#[derive(Clone)]
struct AbcStruct {
data: Arc<Mutex<VecDeque<String>>>,
}
impl AbcStruct {
fn new() -> AbcStruct {
AbcStruct {
data: Arc::new(Mutex::new(VecDeque::new()))
}
}
fn append(&self, new_data: String) {
let mut lock = self.data.lock().unwrap();
lock.push_front(new_data);
}
fn start_thread(&self) {
let me = self.clone();
thread::spawn(move || me.print_data());
}
fn print_data(&self) {
loop {
let lock = self.data.lock().unwrap();
println!("{:?}", &*lock);
}
}
}
fn main() {
let abc = AbcStruct::new();
abc.start_thread();
for i in 0..1000 {
abc.append(format!("{}", i));
}
}
Note that the above code also uses an Arc
to share the data. The way an Arc
works is that every time you clone it, you get a new shared handle to the same inner object. The shared object is destroyed when the last clone of the Arc
is. This is really useful for sharing between multiple threads.
Note that in the above snippet, the background thread is killed when main
returns.