serial dispatch queue
---
title: Serial Dispatch Queue
category: concepts
created: 2026-12-22
updated: 2026-12-22
tags: [serial-dispatch-queue, concurrency, background-processing, thread-safety, dispatch-queue, sequential-processing, audio-processing, real-time-systems]
sources: [raw/conversations/2026-05-06-cursor-gosim-hack-efcdcc83.md]
confidence: high
---
# Serial Dispatch Queue
Concurrency primitive that executes tasks one at a time in FIFO order, guaranteeing sequential execution without the complexity of locks or atomic operations. Essential for processing streaming data where order matters and shared state must be protected.
## Core Characteristics
### Sequential Execution
- Tasks execute one at a time in submission order
- No concurrent access to shared state
- Eliminates race conditions naturally
- Maintains data consistency without explicit synchronization
### Queue Creation
```swift
// Create dedicated serial queue
let processingQueue = DispatchQueue(
label: "com.app.audio-processing",
qos: .userInteractive // High priority for real-time processing
)
// Execute work sequentially
processingQueue.async {
// Process audio chunk 1
}
processingQueue.async {
// Process audio chunk 2 (waits for chunk 1)
}
Audio Processing Applications
Streaming Inference
Perfect for wake-word-detection pipelines where:
- Audio chunks must be processed in temporal order
- Model state (buffers, embeddings) must be updated sequentially
- Real-time constraints require predictable execution
Implementation Pattern
class WakeWordInferenceWorker {
private let processingQueue = DispatchQueue(
label: "wake-word-inference",
qos: .userInteractive
)
func processAudioChunk(_ samples: [Float]) {
processingQueue.async { [weak self] in
self?.pipeline.processSamples(samples)
// Sequential access to rolling buffers
// No race conditions on model state
}
}
}
Performance Characteristics
Quality of Service
.userInteractive: For real-time audio processing.userInitiated: For user-requested operations.utility: For background processing.background: For non-urgent tasks
Thread Management
- System manages underlying thread pool
- Queue may migrate between threads
- No thread affinity guarantees
- Automatic thread lifecycle management
Integration with Swift Concurrency
Actor Alternative
Serial queues provide similar guarantees to actors but with different semantics:
// Serial queue approach
class AudioProcessor {
private let queue = DispatchQueue(label: "audio")
private var buffer: [Float] = []
func process(_ samples: [Float]) {
queue.async {
self.buffer.append(contentsOf: samples)
// Safe: sequential access guaranteed
}
}
}
// Actor approach
actor AudioProcessor {
private var buffer: [Float] = []
func process(_ samples: [Float]) {
buffer.append(contentsOf: samples)
// Safe: actor isolation guaranteed
}
}
Bridging Contexts
// From actor to serial queue
actor MainProcessor {
func handleAudioTap(_ buffer: AVAudioPCMBuffer) {
let samples = extractSamples(buffer)
// Dispatch to background queue
backgroundQueue.async {
processInBackground(samples)
}
}
}
Common Patterns
Worker Pattern
Dedicated queue for specific processing tasks:
- Audio processing worker
- Network request worker
- File I/O worker
- Database transaction worker
Producer-Consumer
class StreamingProcessor {
private let queue = DispatchQueue(label: "streaming")
private var pendingChunks: [AudioChunk] = []
func enqueue(_ chunk: AudioChunk) {
queue.async {
self.pendingChunks.append(chunk)
self.processNextIfReady()
}
}
private func processNextIfReady() {
// Called on queue - no synchronization needed
guard !pendingChunks.isEmpty else { return }
let chunk = pendingChunks.removeFirst()
processChunk(chunk)
}
}
Memory Management
Capture Semantics
- Use
[weak self]to avoid retain cycles [unowned self]for guaranteed lifetime- Copy captured data if lifetime unclear
Resource Cleanup
class ResourceProcessor {
private let queue = DispatchQueue(label: "resources")
deinit {
// Clean shutdown
queue.sync {
cleanupResources()
}
}
}
See also