SimpleLock (object)¶
The SimpleLock is a simple, reentrant, active-wait mutex designed for protecting access to resources that are locked for a relatively small time. The waiting thread will not return to the scheduler, and wait actively. There is no queue, so starvation is possible under sustained access competition.
The SimpleLock is reentrant, and can be acquired by the same thread multiple times. Acquiring a lock multiple times does incur some overhead, so care should be taken to avoid locking when possible if execution speed is important.
Locking is done by passing a SimpleLock to the following functions: Acquire, Release and TryAcquire. The AutoLock wrapper encapsulates the Acquire and Release of a SimpleLock, which can reduce coding the errors (eg: forgetting to release the lock).
The following facilities might be useful for debugging locking problems:
- A .label member (construction parameter) is used to identify the lock when logging errors or tracing.
- A .maxWaitSeconds member (construction parameter) specifies a maximum delay to get the lock. If that delay is passed:
- If .throwAtMaxWait (construction parameter), an exception will be thrown (default)
- Else, an error statement will get printed
- If the Boolean SimpleLock_trace constant is set to true, each lock and unlock actions will be logged
警告
If an exception is thrown by the thread that locked a lock, the lock will remain in a locked state forever. This applies for AutoLock helper since KL won’t cleanup the stack upon exceptions.
The following example shows using locks to ensure that multiple theads can safely write to the same objectin parallel.
/*
** Example: SimpleLock_simpleTest.kl
*/
require FabricSynchronization;
require Math, Util;
object MyThreadsafeObject {
private SimpleLock lock;
private Integer data[];
};
function MyThreadsafeObject (){
this.lock = SimpleLock("MyThreadsafeObject");
}
function MyThreadsafeObject.setData!(Integer index, Integer value){
// Lock in case data is being modified on a different thread.
AutoLock AL(this.lock);
Count oldSize = this.data.size();
if (index >= oldSize)
this.data.resize(index + 1);
this.data[index] = value;
}
function Integer[] MyThreadsafeObject.getData() {
return this.data;
}
// Add date to the object from multiple threads in parallel.
operator dataData<<<index>>>(io MyThreadsafeObject obj) {
obj.setData(index, mathRandomInteger(675435, index));
}
operator entry() {
MyThreadsafeObject obj();
dataData<<<300>>>(obj);
report(obj.getData());
}
/*
** Output:
[198180864,286336441,123095606,142945287,386507260,142128165,505149650,370787731,354354232,35175377,225549742,264185439,267788980,173254845,78238922,29547115,150288752,415573737,147683878,234466743,50250860,112075349,188197314,223063107,212697000,513853185,376553374,411050511,114321188,292323565,223303610,71932699,52868832,474610713,407522838,479322983,391899868,205988997,488554162,184944371,4439832,183707185,480707982,350376383,290860948,4877597,318226090,469651403,208369744,367174985,364627462,253283607,498603340,123124405,214972322,358864291,403227272,200464737,18902910,22066543,222198788,94399821,499255706,379320443,520781248,17965689,525394422,261712583,65684412,321905893,227218578,230692947,476285432,532865169,455933294,24530207,343952500,358711677,135084170,354260267,227198768,177959849,24682982,123649143,201946668,140878613,483284354,11915011,100341096,231095233,140226398,272505039,223518948,415279533,242764666,465446363,313742496,8493273,115475926,250855975,476884124,214627653,307821170,371194291,230057176,379579121,477857102,265492607,439122260,506521053,534921834,33073803,25896464,34050569,142347718,505641943,262858508,57858933,271188834,18454627,482113608,70446625,295403326,429935663,163894724,157627917,225058138,42476347,358169472,263216953,494254518,469297543,77276540,481318309,310407250,268282643,477384632,430064977,403348782,240169951,118666804,55614013,443472970,191336427,27563248,457113705,188615078,247401271,240412652,102130645,534462786,476524995,109374248,55636097,106422046,97472399,156048036,170267245,210730810,231862427,36975200,397833625,360971670,201384167,70102620,444073477,419001906,456207475,349522584,115470257,156386574,524754751,65733396,22584989,464193066,239224139,185537488,156876489,238458246,143223447,297662668,300432437,148508450,209099555,294415880,322454241,336121598,287515375,379809668,26951373,31486234,343117307,410794304,363584505,92590454,140748871,115099452,297404005,347868178,194149843,118576504,276228625,264928494,420371103,493707252,148959997,193904650,459328171,520266416,326094121,433959270,249207287,127900076,478176405,203320578,522179715,269156584,268494145,203837150,200525391,8377444,173849389,123007738,21298011,459886624,447255129,133182806,242827175,475983900,34494149,415248882,150576947,123760728,477705329,250299598,100558335,72469716,511809373,370280938,396042251,45564304,345582473,447438150,420125015,28396172,259448053,245390050,372956643,406365128,163764129,69754558,446249391,429541700,318932877,451216602,320747707,305362688,197433529,457058614,261728007,409839868,520943397,469624786,255758483,234527544,83939025,237804718,74400095,223365556,450005949,187491274,466175339,526708848,468572649,18323750,309422263,363531116,140748117,425187522,127907651,72177320,76945921,361168542,359365903,413847076,505717741,512272058,483870235,135441888,35122969,31894806,287104615,314601948,273540997,426585522,238637555,387438104,405125425,419857550,112782527]
*/
Members¶
UInt32 | state | internal |
Scalar | secondsBetweenChecks | wait time before checking again, to reduce lock competition (constructor argument) |
Scalar | maxWaitSeconds | wait time before an error is triggered (constructor argument) |
Boolean | throwAtMaxWait | if true, errors will be thrown, else printed (constructor argument) |
String | debugName | Label used for traces or error messages |
Methods¶
SimpleLock ( in SimpleLock other ) | |
SimpleLock ( in String debugName ) | |
SimpleLock ( in String debugName, in Scalar maxWaitSeconds ) | |
SimpleLock ( in String debugName, in Scalar maxWaitSeconds, in Boolean throwAtMaxWait ) | |
SimpleLock ( in String debugName, in Scalar maxWaitSeconds, in Boolean throwAtMaxWait, in Scalar secondsBetweenChecks ) | |
SimpleLock () | |
SimpleLock | clone ? () |
cloneMembersTo ? ( io SimpleLock that ) | |
Boolean | locked ? () |
~SimpleLock () |
Methods in detail¶
SimpleLock ( in SimpleLock other )
copy constructor
SimpleLock ( in String debugName )
Constructs a SimpleLock. The default delay between lock checks is 1.0e-6 second. An error will be thrown if a lock can’t be acquired after 5 seconds.
debugName | This name will identify the lock if acquiring fails (maxWaitSeconds) or if logging is enabled (SimpleLock_trace) |
SimpleLock ( in String debugName, in Scalar maxWaitSeconds )
Constructs a SimpleLock. The default delay between lock checks is 1.0e-6 second. An error will be thrown if a lock can’t be acquired after maxWaitSeconds.
debugName | This name will identify the lock if acquiring fails (maxWaitSeconds) or if logging is enabled (SimpleLock_trace) |
maxWaitSeconds | Acquiring delay time in seconds before printing or throwing an error (use SCALAR_INFINITE, or 1e100, for no error reporting). |
SimpleLock ( in String debugName, in Scalar maxWaitSeconds, in Boolean throwAtMaxWait )
Constructs a SimpleLock. The default delay between lock checks is 1.0e-6 second.
debugName | This name will identify the lock if acquiring fails (maxWaitSeconds) or if logging is enabled (SimpleLock_trace) |
maxWaitSeconds | Acquiring delay time in seconds before printing or throwing an error (use SCALAR_INFINITE, or 1e100, for no error reporting). |
throwAtMaxWait | If true, an error will be thrown if a lock can’t be acquired after maxWaitSeconds. Else, the error will only be logged. |
SimpleLock ( in String debugName, in Scalar maxWaitSeconds, in Boolean throwAtMaxWait, in Scalar secondsBetweenChecks )
Constructs a SimpleLock. Acquiring delay errors will be thrown, else an error will be set and logged (using KL’s setError)
debugName | This name will identify the lock if acquiring fails (maxWaitSeconds) or if logging is enabled (SimpleLock_trace) |
maxWaitSeconds | Acquiring delay time in seconds before printing or throwing an error (use SCALAR_INFINITE, or 1e100, for no error reporting). |
throwAtMaxWait | If true, an error will be thrown if a lock can’t be acquired after maxWaitSeconds. Else, the error will only be logged. |
secondsBetweenChecks | Small delay before the lock is tested again (to minimize lock competition: memory cache flushes and CPU synchronization). This number should be smaller if the lock is expected to be held for a small amount of time (eg: 1e-6). |
SimpleLock ()
Constructs a SimpleLock. The default delay between lock checks is 1.0e-6 second. An error will be thrown if a lock can’t be acquired after 5 seconds.
注釈
It is recommended to use constructors that provides a debugName to the lock.
SimpleLock SimpleLock.clone? ()
clone method
SimpleLock.cloneMembersTo? ( io SimpleLock that )
Boolean SimpleLock.locked? ()
Returns ‘true’ if currently locked. However, by the time it returns, another thread might already have changed that state, so it should only be used for heuristic purposes.
~ SimpleLock ()
Destructor. An error will be logged if locked at the moment of destruction.