Ledger: onSync(OnSyncCallback) thread safety

Hi,

from a thread safety point of view, how safe is to change a global variable inside the OnSyncCallback() function of a Ledger? In case I want to read this variable from loop(), for instance.

Thanks!

At worst, the ledger callback will be called from a thread, as it's not an ISR.

As such, you can safely access integral types like int, bool, etc. between threads.

If you are using a complex type like String, Variant, etc. you should use a lock to prevent accessing a partially written variable between two threads.

You should also use a lock, or atomic data types, if you do things like increment or decrement from one thread from two threads.

It's better to use a mutex lock for thread safety. Disabling interrupts should be avoided whenever possible.

Thanks.

So if my class parsing the ledger is a singleton and has these functions+mutex:

public:
    void lock() { os_mutex_lock(mutex); };
    bool tryLock() { return os_mutex_trylock(mutex); };
    void unlock() { os_mutex_unlock(mutex); };
protected:
    os_mutex_t mutex = 0;

Would I use WITH_LOCK(*this) like in the below example?

    Variant cmdVariant;
    WITH_LOCK(*this)
    {
        // Retrieve data from the ledger
        LedgerData ld = ledgerCloudCmd.get();
        const char *key = "cmd";

        // Check if the key exists
        if (!ld.has(key))
        {
            logcc.warn("Key '%s' not found in the ledger", key);
            return false;
        }

        // Get the value
        cmdVariant = ld.get(key);
    }

Thanks!

That should work, but I would probably only put the line where you copy the ledger data into your class member variable in the locked section.

Good point, I will go with this, then:

    LedgerData ld;

    WITH_LOCK(*this)
    {
        // Retrieve data from the ledger
        ld = ledgerCloudCmd.get();
    }

Thank you,

1 Like