Locks

FOR ADVANCED USERS ONLY

These commands allow you to control access to shared resources, preventing conflicts between cogs.

About Locks

A lock is a semaphore mechanism that is used to communicate between two or more entities. In the Propeller chip, a lock is simply one of eight global bits in a protected register within the Hub. The Hub maintains an inventory of which locks are in use and their current states. Cogs can check out, set, clear, and return locks as needed during run time to indicate whether a custom shared item, such as a block of memory, is available or not. Since locks are managed by the Hub only one cog can affect them at a time, making this an effective control mechanism.

In applications where two or more cogs are sharing the same memory, a tool such as a lock may be required to prevent catastrophic collisions from occurring. The Hub prevents such collisions from occurring on elemental data (such a byte, word or long) at every moment in time, but it cannot prevent "logical" collisions on blocks of multiple elements (such as a block of bytes, words, longs or any combination of these). For example, if two or more cogs are sharing a single byte of main memory, each one is guaranteed exclusive access to that byte by nature of the Hub. But if those two cogs share multiple bytes of main memory, the Hub can not prevent one cog from writing a few of those bytes while another cog is reading all of them; all cogs' interactions with those bytes may be interleaved in time. In this case, the developer should design each process (in each cog that shares this memory) so that they cooperatively share the memory block in a non-destructive way. Locks serve as flags that notify each cog when a memory block is safe to manipulate or not.

Suggested Rules for Locks

The following are the suggested rules for using locks.

  • Objects needing a lock to manage a user-defined, mutually exclusive resource should check out a lock using LOCKNEW and save the ID returned, we'll call it SemID here. Only one cog should check out this lock. The cog that checked out the lock must communicate SemID to all other cogs that will use the resource.
  • Any cog that needs to access the resource must first successfully set the lock SemID. A successful "set" is when LOCKSET(SemID) returns FALSE; i.e., the lock was not already set. If LOCKSET returned TRUE, then another cog must be accessing the resource; you must wait and try again later to get a successful "set".
  • The cog that has achieved a successful "set" can manipulate the resource as necessary. When done, it must clear the lock via LOCKCLR(SemID) so another cog can have access to the resource. In a well-behaved system, the result of LOCKCLR can be ignored here since this cog is the only one with the logical right to clear it.
  • If a resource is no longer needed, or becomes non-exclusive, the associated lock should be returned to the lock pool via LOCKRET(SemID). Usually this is done by the same cog that checked out the lock originally.

Applications should be written such that locks are not accessed with LOCKSET or LOCKCLR unless they are currently checked out.

Note that user-defined resources are not actually locked by either the Hub or the checked-out lock. The lock feature only provides a means for objects to cooperatively lock those resources. It's up to the objects themselves to decide on, and abide by, the rules of lock use and what resource(s) will be governed by them. Additionally, the Hub does not directly assign a lock to the cog that called LOCKNEW, rather it simply marks it as being "checked out" by a cog; any other cog can "return" locks to the pool of available locks. Also, any cog can access any lock through the LOCKCLR and LOCKSET commands even if those locks were never checked out. Doing such things is generally not recommended because of the havoc it can cause with other, well-behaved objects in the application.

Unless otherwise noted, content on this site is licensed under the
Creative Commons Attribution-ShareAlike 4.0 International License.