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.