Course contentsShow
← Rust
Lesson 1122 of 1,91010. Concurrency PrimitivesFree lesson

Prioritized Task Queuing

You will implement custom scheduling within channels to ensure urgent work is processed first.

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

  1. The Heap: By using std::collections::BinaryHeap, we ensure that the task with the highest value (determined by your Ord implementation) is always at the top.
  2. The Mutex: Since multiple producers might be adding tasks, the Mutex ensures thread-safe access to the internal BinaryHeap.
  3. The Condvar: When a consumer calls pop() and finds an empty heap, it parks the thread using the Condvar. When a producer pushes a new item, it calls notify_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.