uOwnerLock
uOwnerLock is uC++‘s blocking, multiple-acquisition mutex lock. The task that acquired the lock can acquire it again without deadlocking, which makes it safe for recursion and for code paths where one locked function calls another that also locks the same resource. Each acquire must be matched by a release.
Why multiple acquisition instead of single?
A single-acquisition mutex deadlocks on recursion. If
f()holds the lock and callsg()which also tries to acquire the same lock, the task waits for itself forever. Owner locks track who holds the lock and an acquisition count, so the owner can re-enter freely. The cost is a few extra bytes of state and a branch on each acquire.
Interface
class uOwnerLock {
public:
uOwnerLock();
uBaseTask * owner(); // task holding lock, or nullptr
unsigned int times(); // # acquisitions by current owner
void acquire(); // blocks if another task owns
bool tryacquire(); // non-blocking attempt
void release(); // must be called once per acquire
};Usage
uOwnerLock lock;
void g() {
lock.acquire(); // re-entrant, no deadlock
// ...
lock.release();
}
void f() {
lock.acquire();
g(); // safe: same owner, times() goes 1 → 2 → 1
lock.release();
}Owner vs spinlock
Same external API as uLock, but with blocking instead of spinning on a failed acquire. A contending task is put on the lock’s blocked queue and descheduled, rather than looping. This is the default choice for any critical section long enough that spinning would waste more CPU than blocking costs.
Always release
Exceptions, early returns, or breaks can skip a plain lock.release(). Use one of the release patterns (_Finally or RAII) to guarantee release on every exit path.