Introduction
This article shows a C++ class that provides access to named locks on a Shared and Exclusive basis within a process. The function is similar to the IBM OS/390 ENQ/DEQ macros.
- RET=HAVE is implied.
- The lock name is LOCKNAME/LOCKNAME_LENGTH pair rather than a QNAME/RNAME/RNAMEL combination.
A thread can request exclusive or shared ownership of a lock. Ownership is granted based on the following table:
|
Request |
Held by other threads |
Action |
|
EXCLUSIVE |
NONE |
Granted |
|
EXCLUSIVE |
ANY |
Wait |
|
SHARED |
NONE/SHARED |
Granted |
|
SHARED |
EXCLUSIVE (any) |
Wait |
Threads placed in a wait state are released when the lock becomes available. Any EXCLUSIVE request blocks all requests following it until the EXCLUSIVE request is released.
Background
Written in ANSI C++, except for the three internal classes described below.
Needed to be able to refine the Windows CRITICAL_SECTION function into shareable and exclusive locks for thread control.
Can be ported to other environments with minimal changes.
Replace:
- Internal class
EXCLUSIVE_EX.
- Internal class
Semaphore.
- Internal class
ThreadIdentity
Using the code
Lock names may contain binary codes, for instance, an address. All compares, copies, etc. use the mem*** C++ functions. The maximum length for a lock name is 64 bytes (parameterized within locker.h).
How to use Locker:
In the parent thread, create an instance of the Locker class.
Locker *Lockset;
Lockset=new Locker()
Pass Lockset to child threads that need access to the locks.
In any thread with access to Lockset:
int rc;
rc=Lockset->GetSharedLock(const char *lname, int lnamel);
Returns LOCK_OK (lock established)
LOCK_SHARED (Shared lock already held)
LOCK_EXCL (Exclusive lock already held)
LOCK_ERROR (LNAMEL > MAXLOCKNAME)
rc=Lockset->GetExclLock(const char *lname, int lnamel);
Returns LOCK_OK (lock established)
LOCK_SHARED (Shared lock already held)
The lock state was NOT changed
to Exclusive, and remains in
effect as Shared.
LOCK_EXCL (Exclusive lock already held)
LOCK_ERROR (LNAMEL > MAXLOCKNAME)
rc=Lockset->RelLock(const char *lname, int lnamel);
Returns LOCK_OK (lock released)
LOCK_NOT_HELD (lock wasn't held)
LOCK_ERROR (LNAMEL > MAXLOCKNAME)
rc=Lockset->TestLock(const char *lname, int lnamel);
Returns LOCK_SHARED (Shared lock held)
LOCK_EXCL (Exclusive lock held)
LOCK_NOT_HELD (lock wasn't held)
LOCK_ERROR (LNAMEL > MAXLOCKNAME)
When all threads are no longer using the Lockset:
delete Lockset;
If any threads are still using the Lockset, the destructor terminates the process with an assert(0), preventing program checks in the active threads when they attempt to access the deleted class.
History
- First release.
- Version 1.1
- Fixed a bug that caused a loop during
RelLock
- Performance enhancement and code simplification - changed
RelLock to not remove the Lock structure when no users of a lock remain. Lock structures are now removed a destructor time only.
- Updated Locker.h Locker.cpp to move all Windows-specific code into Locker internal classes, making ports to other systems easier.
- Updated Tlocker.cpp to use the data base address as the lock.
- Added tlocker_readme.txt file to describe the test program and how to run it.
- Created a separate VC workspace that contains only the Locker project (Locker.dws, Locker.dsp, and Tlocker.dsp).
Application and systems programmer since 1972.
Mostly mainframe programming - Assembler, PL/X.
Products: IBM: DFSMSHSM, Candle Corp: Omegamon (IMS and MVS), PKWARE: SecureZIP
Dabble in Windows and Linux at home - C++ and Intel Assembler.