Lock Object

class Lock extends Object

A mutual-exclusion lock for code shared between real threads.

This class is exported by the KS module.

Call

LockObj := Lock()

Creates a lock. Share the same object between the threads which must not run the guarded code concurrently.

Acquire

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.

Release

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.

Holding a lock for one call

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()
}

Remarks

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.

Examples

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()
}

RealThread, Await, Critical, Threads