Skip to content

Instantly share code, notes, and snippets.

@rawnly
Created January 21, 2023 21:33
Show Gist options
  • Save rawnly/2619f40f90d203a071036bdb211c152f to your computer and use it in GitHub Desktop.
Save rawnly/2619f40f90d203a071036bdb211c152f to your computer and use it in GitHub Desktop.
- data: VecDeque<T>
+ data: Mutex<VecDeque<T>>
+ cv: CondVar
- fn pop(&self) -> Option<T>;
+ fn pop(&self) -> T;
///! queue/mod.rs
use std::collections::VecDeque;
/// A FIFO queue implemented using a VecDeque
struct FifoQueue<T> {
 /// The underlying data structure of the queue
 data: VecDeque<T>
}
///! queue/mod.rs
use std::{ thread, sync::Arc, time::Duration };
#[cfg(test)]
mod test {
use crate::queue::prelude::*;
use crate::queue::FifoQueue;
use std::{sync::Arc, thread};
#[test]
fn test_queue_thread_safety() {
// create a queue of numbers
let queue = Arc::new(FifoQueue::<i32>::new());
let q1 = queue.clone();
let t1 = thread::spawn(move || {
q1.push(1);
q1.push(2);
});
let q2 = queue.clone();
let t2 = thread::spawn(move || {
q2.push(3);
q2.push(4)
});
t1.join().unwrap();
t2.join().unwrap();
assert_eq!(queue.len(), 4);
}
}
///! queue/mod.rs
use std::{ collections::VecDeque, sync::{Mutex, CondVar} };
/// includes common traits
pub mod prelude;
// import our Queue<T> trait
use self::prelude::*;
struct FifoQueue<T> {
data: Mutex<VecDeque<T>>,
/// The condvar used to signal when the queue is not empty
cv: CondVar
}
impl<T> Queue<T> for FifoQueue<T> {
fn new() -> Self {
Self {
data: Mutex::new(VecDeque::new()),
cv: CondVar::new()
}
}
/// push input on the back of the queue
/// - unrecoverable if lock fails so just unwrap
fn push(&self, value: T) {
let mut data = self.data.lock().unwrap();
data.push_back(value)
// notify the thread that the queue has been populated
self.cv.notify_one();
}
/// pop element from the queue
/// - unrecoverable if the lock fails so just unwrap
/// - same for condvar variable
fn pop(&self) -> T {
let mut data = self.data.lock().unwrap();
// wait for the notification if the queue is empty
while data.is_empty() {
data = self.cv.wait(data).unwrap();
}
data.pop_front().unwrap()
}
fn len(&self) -> usize {
let data = self.data.lock().unwrap();
data.len()
}
fn is_empty(&self) -> bool {
let data = self.data.lock().unwrap();
data.is_empty()
}
}
///! queue/prelude.rs
impl<T> Queue<T> for FifoQueue<T> {
fn new() -> Self {
Self {
data: VecDeque::new()
}
}
/// Adds an element to the back of the queue
fn push(&self, value: T) {
self.data.push_back(value)
}
/// Removes an element from the front of the queue
fn pop(&self) -> Option<T> {
self.data.pop_front()
}
fn len(&self) -> usize {
self.data.len()
}
fn is_empty(&self) -> bool {
self.data.is_empty()
}
}
trait Queue<T> {
 /// Creates a new, empty queue
 fn new() -> Self;
 
 /// Enqueue a new value
 fn push(&self, value: T);
 
 /// Dequeue a value 
 /// Returns None if the queue is empty
 fn pop(&self) -> Option<T>;
 
 /// Returns the number of elements enqueued
 fn len(&self) -> usize;
 
 /// Checks if the `size()` is 0
 fn is_empty(&self) -> bool;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment