It frequently occurs that I need to control access to a data structure that holds several related members, to prevent a task from reading its members while it is being updated. If that were to happen then an inconsistent set of members could be read, for example the variable holding the count of used elements in an array might not reflect the actual number of valid elements.
Where the time spent accessing the data structure is small, I can accomplish this by suspending the scheduler before the start of accessing or updating the data, and un-suspending the scheduler after completing it. However, access to the structure sometimes involves iterating through elements of arrays in the structure, so this is undesirable.
It’s typically rare that the data structure gets updated, but there may be several tasks reading the structure to report on it. Therefore, to avoid unnecessary task blocking and switching, I don’t want to enforce mutual exclusion between readers of the structure. What I need is a type of lock that supports two types of lock: read-locks and write-locks. Multiple tasks may hold read-locks on the object, OR one task may hold a write-lock.
I have implemented such a locking structure in my own code, using a combination of atomic variables to handle multiple readers without having to call FreeRTOS mutex functions, and a FreeRTOS Mutex to handle the situation when a write lock is owned or pending. The code is public if anyone wants it. Here’s an abbreviated summary of what I have implemented:
- A task may request a read lock on the object. The lock will be granted if there is no existing or pending write lock on the object.
- A task may request a write lock on the object. The lock will be granted if there are no read or write locks currently on the object. Otherwise the lock will be pending and the caller task suspended until these conditions are met.
- Tasks may relinquish their locks. A task that owns a write-lock on an object may downgrade it to a read lock.
However, my code (and the above specification) doesn’t correctly handle task priorities, except in the case of multiple tasks requesting write locks. For example, it doesn’t allow any new read locks if a write lock is pending, even if the task requesting a read lock has a higher priority than the task with the pending write lock.
It would be great if this functionality could be made an optional feature of FreeRTOS and the priority issues resolved. The main implementation difficulty I see is that the amount of memory needed to track existing and pending locks is not fixed but depends on the maximum number of tasks that can make lock requests.
My current project uses 40+ instances of this type of lock. I can’t be the only person with a use for this type of lock because I see that the Java ReadWriteLock class implements essentially the same functionality.
Please can this be added to the list of features to be included in a future release of FreeRTOS.