komora_sync/
segmented_priority_queue.rs1use std::collections::BinaryHeap;
2use std::sync::{Condvar, Mutex};
3
4use crate::Prioritized;
5
6#[derive(Debug)]
9pub struct SegmentedPriorityQueue<T> {
10 reader: Mutex<BinaryHeap<Prioritized<T>>>,
11 writer: Mutex<BinaryHeap<Prioritized<T>>>,
12 cv: Condvar,
13}
14
15impl<T> Default for SegmentedPriorityQueue<T> {
16 fn default() -> Self {
17 Self::new()
18 }
19}
20
21impl<T> SegmentedPriorityQueue<T> {
22 pub fn new() -> SegmentedPriorityQueue<T> {
23 SegmentedPriorityQueue {
24 reader: Mutex::default(),
25 writer: Mutex::default(),
26 cv: Condvar::new(),
27 }
28 }
29
30 pub fn push(&self, t: T, priority: u64) {
68 let mut q = self.writer.lock().unwrap();
69 q.push(Prioritized { t, priority });
70 drop(q);
71 self.cv.notify_one();
72 }
73
74 pub fn pop(&self) -> T {
75 let mut q = self.reader.lock().unwrap();
76
77 while q.is_empty() {
78 let mut q2 = self.writer.lock().unwrap();
80
81 std::mem::swap(&mut *q, &mut *q2);
82
83 drop(q2);
84
85 if q.is_empty() {
86 q = self.cv.wait(q).unwrap();
87 }
88 }
89
90 q.pop().unwrap().t
91 }
92}
93
94#[test]
95fn segmented_priority_queue_concurrent_pops() {
96 use std::sync::atomic::{AtomicU64, Ordering};
97 use std::sync::{Arc, Barrier};
98
99 const N_WRITES_PER_WRITER: u64 = 1_000_000;
100 const N_WRITERS: u64 = 10;
101 const N_WRITES: u64 = N_WRITERS * N_WRITES_PER_WRITER;
102 const N_READERS: u64 = 10;
103
104 let q = Arc::new(SegmentedPriorityQueue::new());
105 let barrier = Arc::new(Barrier::new(N_WRITERS.try_into().unwrap()));
106 let read = Arc::new(AtomicU64::new(0));
107
108 for i in 0..N_WRITERS {
109 let q = q.clone();
110 let barrier = barrier.clone();
111 std::thread::spawn(move || {
112 barrier.wait();
113
114 for j in 0..N_WRITES_PER_WRITER {
115 q.push(i * j, i);
116 }
117 });
118 }
119
120 for _ in 0..N_READERS {
121 let q = q.clone();
122 let read = read.clone();
123 std::thread::spawn(move || loop {
124 q.pop();
125 read.fetch_add(1, Ordering::SeqCst);
126 });
127 }
128
129 while read.load(Ordering::SeqCst) < N_WRITES {
130 std::hint::spin_loop();
131 }
132}