class Lock extends Object
A mutual-exclusion lock for code shared between real threads.
This class is exported by the KS module.
LockObj := Lock()
Creates a lock. Share the same object between the threads which must not run the guarded code concurrently.
Acquired := LockObj.Acquire(Timeout)
Acquires the lock, returning 1 (true) once held or 0 (false) if Timeout elapsed first. Timeout is in milliseconds; omit it to wait indefinitely.
Warning: This blocks the whole real thread, not just the calling script thread. Acquiring on the main thread stalls the script's message loop until it succeeds, so pass a timeout there rather than waiting indefinitely on work a worker might be slow to finish.
LockObj.Release()
Releases the lock once. Must be called by the real thread that acquired it, once per successful Acquire. Releasing a lock this thread does not hold is an error.
To hold a lock for the duration of one call, release it from a finally so that it is released even if the callback throws:
LockedCall(lock, callback, args*)
{
lock.Acquire()
try
return callback(args*)
finally
lock.Release()
}
The lock belongs to a real thread, not to a script thread, and it is reentrant: the same real thread may acquire it repeatedly and must release it once per acquisition.
Warning: Because ownership is per real thread, a thread that interrupts a lock holder on the same real thread — a timer or hotkey — counts as the same owner. It can re-enter the lock, and a Release there releases the interrupted thread's acquisition. Keep guarded sections short and do not let one span a point where the thread can be interrupted, or make the interrupting thread Critical.
Giving up rather than stalling the main thread.
#Import "Ks" { RealThread, Lock, Await }
global stateLock := Lock(), state := 0
worker := RealThread(Produce)
if stateLock.Acquire(100) {
try
MsgBox "state is " state
finally
stateLock.Release()
} else
MsgBox "worker is still busy; try again later"
Await(worker.Task)
Produce() {
stateLock.Acquire()
try {
Sleep 500
state := 42
} finally
stateLock.Release()
}