Main reason behind using message buffers over queues would be if the data being stored is of a variable size as opposed to fixed, yes?
How come it’s only safe for message buffers to be accessed by a single reader/writer and not multiple ones unless you lock? xStreamBufferSend() seems to have a critical section inside which should be taking care of single access, no?
Why there’s no need for a lock inside xStreamBufferSendFromISR()? Because there can only be one interrupt at a time?
Your second and third are related. The reason stream/message buffers are only safe for single reader/single writer is that the don’t have the lock inside, which isn’t needed for that simple case, which makes the code more efficient.
The variable sized buffer has been a frequent request, and this provided an answer to that.
The single reader/single write is actually a fairly common case, and if you do have multiple writers or readers, putting a mutex around the buffer access (separate mutex for read and/or write) allows you to use multiple accessors.
Personally, I would likely only have multiple writers, though I suppose you might have multiple readers if you created multiple copies of a task to allow some concurrency in processing the messages.
xStreamBufferSend() has a taskENTER_CRITICAL which seemingly disables the interrupts but doesn’t seem like it’s a mutex lock. Though taskENTER_CRITICAL is also used in xQueueGenericSend() so how come multiple access to queues is fine but not with message buffers?
Compare what is done in the critical sections. in xStreamBufferSend, the code is basically jus checking for space, and if there isn’t to goes straight to a TaskNotifyWait.
In XQueueGenericSend, there is a lot more code, including manipulating lists of tasks blocked on the queue. THAT is the overhead of multiple access, and is basically the code to implement a mutex (Semaphores/Mutexes are basically Queue with no data)
Richard-Damon is right here - queues and semaphores are complex legacy objects because they have priority lists of tasks waiting to send and priority lists of tasks waiting to receive - plus they are thread aware in excess of the traditional meaning of ‘thread aware’ because if a task is unblocked because space because available in a queue there is no guarantee space will still be available when the unblocked task starts to run.
With stream/message buffers and direct to task notifications we aim to provide much lighter weight alternatives to the legacy inter task communication and synchronisation primitives by coding for the most common use cases, rather than a generic use case.
With reference to the critical section you mention - from memory (need to check the code) that is used to make checking to see if the stream buffer is empty (or full) and blocking on the stream buffer an atomic operation. Otherwise a task might write to the buffer between the reading task deciding the buffer is empty and blocking - although I think I we can actually re-write that part slightly to remove the need for the critical section at all.
Does taskENTER_CRITICAL act as a lock? I see it’s only disabling interrupts.
There’s no taskENTER_CRITICAL in the xStreamBufferSendFromISR() since one interrupt happens at a time so there’s no way the data could be manipulated by another task? Is that the reason?
Also, doesn’t message passing techniques via message buffer/queues act more as a signalling mechanism similar to semaphores? You could block a task on a message buffer which would get unlocked upon message buffer getting populated (signalling)? I haven’t used semaphores in FreeRTOS but was curious