In this lesson, you will learn how to bypass standard FIFO (First-In, First-Out) channel processing by implementing a prioritized task queue using a thread-safe binary heap.
The Problem with Standard Channels
Standard MPSC or MPMC channels are strictly FIFO. If a high-priority "System Shutdown" or "Critical Update" message is sent after a thousand "Log Data" messages, it must wait for every preceding task to finish. When you need urgent tasks to jump the line, you need a custom queue structure that supports sorting by priority.
Building a Prioritized Channel
Instead of a simple channel buffer, we wrap a BinaryHeap inside a Mutex along with a Condvar to manage the signaling. This allows threads to block efficiently when the queue is empty, avoiding the "thundering herd" or high-CPU spin-looping.
use std::collections::BinaryHeap;
use std::sync::{Arc, Mutex, Condvar};
struct PriorityQueue<T: Ord> {
heap: Mutex<BinaryHeap<T>>,
cvar: Condvar,
}
impl<T: Ord> PriorityQueue<T> {
fn push(&self, item: T) {
self.heap.lock().unwrap().push(item);
self.cvar.notify_one();
}
fn pop(&self) -> T {
let mut heap = self.heap.lock().unwrap();
while heap.is_empty() {
heap = self.cvar.wait(heap).unwrap();
}
heap.pop().unwrap()
}
}
How it works
- The Heap: By using
std::collections::BinaryHeap, we ensure that the task with the highest value (determined by yourOrdimplementation) is always at the top. - The Mutex: Since multiple producers might be adding tasks, the
Mutexensures thread-safe access to the internalBinaryHeap. - The Condvar: When a consumer calls
pop()and finds an empty heap, it parks the thread using theCondvar. When a producerpushes a new item, it callsnotify_one(), waking a consumer to evaluate the new, potentially highest-priority task.
This pattern effectively turns a standard FIFO messaging system into a responsive priority-aware scheduler. By assigning integers or custom enums as priority levels, you gain fine-grained control over which tasks occupy your workers' time, ensuring latency-sensitive work never gets stuck behind bulk data processing.
Key Takeaway: Use a BinaryHeap protected by a Mutex and Condvar to implement a priority queue that allows critical tasks to preempt standard processing in a multi-threaded environment.