I am a tad confused about how to share a structure between threads such that one thread can update the structures internal data and the second thread can respond to the updates.
The program is reading large blocks of data from a device driver. The reader thread stores the latest data in one of 2 buffers. The response thread uses the buffer which is not currently being used by the other thread:
struct RawBuffer {
buffer_a_: Arc<Mutex<Vec<u8>>>,
buffer_b_: Arc<Mutex<Vec<u8>>>,
using_buffer_a_: AtomicBool,
}
pub struct Reader {
device_file_: File,
buffer_: RawBuffer,
counter_: usize,
}
impl Reader {
pub fn read_frame(&mut self) {
let mut guard = match self.buffer_.using_buffer_a_.load(
Ordering::Relaxed) {
true => self.buffer_.buffer_a_.lock().unwrap(),
false => self.buffer_.buffer_b_.lock().unwrap(),
};
match self.device_file_.read(&mut *guard) {
Ok(_) => { self.counter_ += 1; }
Err(err) => println!("Failed to read file '{}', error = {:?}",
DEVICE_FILE, err),
}
}
pub fn apply<F>(&self, f: F) where F: Fn(&Vec<u8>) {
let guard = match self.buffer_.using_buffer_a_.load(
Ordering::Relaxed) {
true => self.buffer_.buffer_b_.lock().unwrap(),
false => self.buffer_.buffer_a_.lock().unwrap(),
};
let buf = & *guard;
f(buf);
}
}
If the calls to read_frame()
and apply()
are in the same thread everything works, e.g.:
fn reader_thread() {
let mut reader = Reader::new();
for _ in 0..1000 {
reader.read_frame();
reader.apply(|buf| {
// do stuff with buffer
});
}
}
When I try to create the reader in my main function such that the apply()
method can be called independently, the code fails to compile because the reader thread needs exclusive mutable access, e.g. reader_thread()
becomes:
fn read_frames(reader: Arc<frame_reader::Reader>,
window: Arv<Window>) {
let num_frames = 6000;
for _ in 0..num_frames {
reader.read_frame();
window.request_redraw();
}
}
which generates the following error:
Compiling dummy_frame_writer v0.1.0 (/mnt/data-001/Views/View01/ngh-dummy-driver/utils/dummy_frame_writer)
error[E0596]: cannot borrow data in anArc
as mutable
--> src/main.rs:134:9
|
134 | reader.read_frame();
| ^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
The main()
thread needs to update the display whenever a redraw is requested, ergo it needs non-mutable access to the buffer in the reader object:
fn main() {
let reader = Arc::new(frame_reader::Reader::new();
// create window and event loop
let handle = thread::spawn(move || { reader_thread(reader.clone(), window.clone()); });
event_loop.run(move |event, _, control_flow| {
// code removed ....
Event::RedrawRequested(_) => {
reader.apply(|buf| {
// display buffer details.
});
},
_ => ()
}
});
}
How should I structure the code so that the reader can update each buffer and a second thread can use the updated data? Note, reader itself cannot be placed in a Arc<Mutex>
because I need to independently lock each buffer...
So far the only mechanism I can think of is to make RawBuffer
independent of Reader but that feels wrong.