In this lesson, you will learn how to leverage stream buffers to move byte-oriented data between tasks with maximum efficiency by eliminating redundant memory copying.
The Problem: The Cost of Copies
When using standard RTOS queues, data is typically copied twice: first from the producer task into the queue, and then from the queue into the consumer’s local buffer. In high-throughput systems—such as processing streaming audio or high-speed sensor packets—these memcpy operations consume significant CPU cycles and add non-deterministic latency. As you learned in our discussions on Worst-Case Execution Time (WCET), every instruction counts.
The Solution: Stream Buffers
Stream buffers are designed specifically for byte-stream communication between a single producer and a single consumer. Unlike a queue that handles discrete "items," a stream buffer treats data as a continuous flow.
The "Zero-Copy" magic occurs when the buffer allows the consumer to access the internal memory directly. Instead of pulling data out of the stream buffer into a separate array, the consumer receives a pointer or an offset into the buffer’s internal storage. By working directly within the buffer’s memory space, you bypass the intermediate staging area entirely.
Conceptual Implementation
In a typical zero-copy implementation, the producer writes into the buffer until a threshold is met, and the consumer processes it in place:
/* Pseudocode for zero-copy stream processing */
size_t bytesAvailable;
uint8_t *bufferPtr;
// Producer adds data directly to the stream buffer
xStreamBufferSend(xStreamBuffer, dataPtr, dataLength, ticksToWait);
// Consumer retrieves a pointer to the data instead of copying it
bytesAvailable = xStreamBufferReceive(xStreamBuffer, &bufferPtr, ...);
if (bytesAvailable > 0) {
// Process the data in-place using the pointer
ProcessData(bufferPtr, bytesAvailable);
// Mark as consumed, freeing the space for new data
xStreamBufferRelease(xStreamBuffer, bytesAvailable);
}
By using xStreamBufferRelease, the system effectively "clears" the space in the buffer without moving a single byte of application data. This approach is highly effective for minimizing jitter and keeping your system responsive under heavy loads.
Key Takeaway: Stream buffers optimize performance by allowing tasks to reference internal data pointers directly, removing the latency penalties associated with copying large memory blocks.