Suppose having the following code elements working on a fifo buffer:
static uint_fast32_t buffer_start;
static uint_fast32_t buffer_end;
static mutex_t buffer_guard;
(...)
void buffer_write(uint8_t* data, uint_fast32_t len)
{
uint_fast32_t pos;
mutex_lock(buffer_guard);
pos = buffer_end;
buffer_end = buffer_end + len;
(...) /* Wrap around buffer_end, fill in data */
mutex_unlock(buffer_guard);
}
bool buffer_isempty(void)
{
bool ret;
mutex_lock(buffer_guard);
ret = (buffer_start == buffer_end);
mutex_unlock(buffer_guard);
return ret;
}
This code might be running on an embedded system, with a RTOS, with the buffer_write()
and buffer_isempty()
functions called from different threads. The compiler has no means to know that the mutex_lock()
and mutex_unlock()
functions provided by the RTOS are working with a critical sections.
As the code is above, due to buffer_end
being a static
variable (local to the compilation unit), the compiler might choose to reorder accesses to it around function calls (at least as far as I understand the C standard, this seems possible to happen). So potentially the code performing buffer_end = buffer_end + len
line have a chance to end up before the call to mutex_lock()
.
Using volatile
on these variables (like static volatile uint_fast32_t buffer_end;
) seems to resolve this as then they would be constrained by sequence points (which a mutex_lock()
call is, due to being a function call).
- Is my understanding right on these?
- Is there a more appropriate means (than using
volatile
) of dealing with this type of problem?