Course contentsShow
← Embedded Systems & Computer Architecture
Lesson 519 of 9367. Real-Time Operating Systems (RTOS)Free lesson

Achieving Zero-Copy Data Transfer with Stream Buffers

Utilize stream buffers to handle continuous byte-oriented data streams between tasks without the overhead of copying large memory blocks.

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.