System thread
Synchronizing access to shared system resources
With system threading enabled, the system thread and the application thread run in parallel. When both attempt to use the same resource, such as writing a message to Serial
, there is no guaranteed order - the message printed by the system and the message printed by the application are arbitrarily interleaved as the RTOS rapidly switches between running a small part of the system code and then the application code. This results in both messages being intermixed.
This can be avoided by acquiring exclusive access to a resource. To get exclusive access to a resource, we can use locks. A lock ensures that only the thread owning the lock can access the resource. Any other thread that tries to use the resource via the lock will not be granted access until the first thread eventually unlocks the resource when it is done.
There are a number of shared resources that can be used by the system. These include:
Serial
when using listening mode, or when usingSerialLogHandler
.SPI
on some devices that use Ethernet.Wire
(I2C) on some devices that use a PMIC and fuel gauge on primary I2C.PMIC
on devices that use the system power manager and the bq24195 PMIC.
This example shows how to use locking to share the UART serial port Serial
between two threads.
void print_status()
{
WITH_LOCK(Serial) {
Serial.print("Current status is:");
Serial.println(status);
}
}
The primary difference compared to using Serial without a lock is the WITH_LOCK
declaration. This does several things:
attempts to acquire the lock for
Serial
. If the lock isn't available, the thread blocks indefinitely until it is available.once
Serial
has been locked, the code in the following block is executed.when the block has finished executing, the lock is released, allowing other threads to use the resource.
It's also possible to attempt to lock a resource, but not block when the resource isn't available.
TRY_LOCK(Serial) {
// this code is only run when no other thread is using Serial
}
The TRY_LOCK()
statement functions similarly to WITH_LOCK()
but it does not block the current thread if the lock isn't available. Instead, the entire block is skipped over.