I designed this simple fifo that stores a DequePolicy
, which is simply something that can remove elements from the back if there are too much elements:
use super::deque_policy::DequePolicy;
use std::collections::VecDeque;
use std::sync::Arc;
use std::sync::Condvar;
pub struct BoundedFifo<T> {
pub deque: VecDeque<T>,
pub policy: Box<dyn DequePolicy<T>>,
//pub condvar: Condvar
}
impl<T> BoundedFifo<T> {
pub fn new(policy: Box<dyn DequePolicy<T>>) -> BoundedFifo<T> {
BoundedFifo{
deque: VecDeque::<T>::new(),
policy: policy,
//condvar: Condvar::new()
}
}
}
impl<T> BoundedFifo<T> {
pub fn pop_front(&mut self) -> Option<T> {
self.policy.before_pop_front(&self.deque);
//self.condvar.notify_all();
self.deque.pop_front()
}
pub fn push_back(&mut self, t: T) {
self.deque.push_back(t);
//self.condvar.notify_all();
self.policy.after_push_back(&mut self.deque);
}
}
I want to share this fifo between 2 threads, but there's a problem. I want one thread to be able to wait for elements to be present on the fifo. That's why I added the condvar
that is commented right now.
I commented it because I quickly realized that to share the fifo
between threads, I gotta put it inside an Arc<Mutex<>>
. So in order to wait for condvar
that is inside fifo: Arc<Mutex<BoundedFifo<u8>>>
for example, I'd have to lock it on one thread: fifo.lock().unwrap().condvar.wait_timeout(...)
. This essentially prevents the other thread from writing so there would be no point in waiting.
I then had the idea to do:
type Fifo<T> = Arc<(Mutex<BoundedFifo<T>>, Condvar)>;
Now I can wait for a condvar, but I also have to remember of notifying this condvar whenever I call fifo: Fifo<T>
's push_back
and pop_front
. For example:
let pair = ...
let fifo = pair.0;
let condvar = pair.1;
fifo.push_back(0);
condvar.notify_all();
this is error prone as I could easily forget to call it. On C++ it'd let me wait for something inside the shared thing (even though this is unsafe).
I thought about creating macros push_back!
and pop_front!
that would push_back
and pop_front
together with calling notify_all
on the condvar
, but I don't find this very elegant.
I'm kinda new to Rust, so I'm asking for better solutions for this. Is it possible, for example, to implement push_back
and pop_front
for Fifo<T>
? This way I avoid macros :slight_smile:. That's an idea.