Scope guards that borrow the supplied object, temporarily acquire or release its locking, and perform the opposite operation on destruction.
Guard model
Fields
object: reference to the object used for the initial and paired locking calls. The stored view must permit both calls, and the target must outlive the guard.
The guard holds a view of the supplied object; it does not copy or own that object. An in-place argument remains a separately owned value in the enclosing scope. The object must remain alive at the same address until the guard is destroyed. A factory may return a guard over a caller-owned object, but not over an object local to the factory.
lockGuardandlockSharedGuardacquire first and release on destruction.unlockGuardandunlockSharedGuardrelease first and reacquire on destruction.- The initial lock or unlock operation is completed before the guard is returned.
- Guard destruction performs the paired opposite operation exactly once and returns no additional status value.
- No additional lock resource is created by the helper itself.
Guard contracts
Method contract
- The supplied view must permit both method calls. The methods take no explicit arguments; the shown stack effects assume that the initial method returns nothing. Any values it does return remain below guard on the stack and are not interpreted as success or failure. The method called on destruction must return nothing.
Lifetime
- The initial operation is performed during construction; these guards define
DIEbut noINITorASSIGN. Bind the fresh guard directly in the scope that should control its lifetime. An existing guard is neither copyable nor movable withnewor assignment.dropremoves the stack item but does not immediately destroy the guard; the paired operation still runs when the guard's lifetime ends. A factory may return a fresh guard provided the referenced lock object remains alive.
Compatibility
- The object's locking methods determine whether each acquisition, release or nested use is valid. unlockGuard and unlockSharedGuard require the corresponding release to be valid on entry and reacquisition to be valid at destruction. The guards do not check lock ownership, recursion or acquisition success, and do not suppress the paired operation based on a returned status.
- Errors or blocking behavior of provided methods belong to those methods, not to a separate guard failure protocol.
lockGuard
(object -- guard) Calls lock and returns a guard that calls unlock on destruction.unlockGuard
(object -- guard) Calls unlock and returns a guard that calls lock on destruction.Examples
The example passes Ref to each DummyLock local so each guard operates on that existing local object.
Compile-time guard transitions
"control" use
"lockGuard" use
DummyLock: [{
state: 0i32;
lock: [1 !state];
unlock: [0 !state];
lockShared: [2 !state];
unlockShared: [0 !state];
}];
{} () {} [
a: DummyLock;
@a lockGuard drop
a.state printStack _:;
b: DummyLock;
@b lockSharedGuard drop
b.state printStack _:;
c: DummyLock;
1 @c.!state
@c unlockGuard drop
c.state printStack _:;
d: DummyLock;
2 @d.!state
@d unlockSharedGuard drop
d.state printStack _:;
] "main" exportFunction
Expected Output During Compilation
1 Cref
2 Cref
0 Cref
0 Cref
Runtime example
"String" use
"control" use
"lockGuard" use
DummyLock: [{
state: 0i32;
lock: [1 !state];
unlock: [0 !state];
lockShared: [2 !state];
unlockShared: [0 !state];
}];
{} Int32 {} [
a: DummyLock;
[
g0: @a lockGuard;
("locked=" a.state LF) printList
] call
("unlocked=" a.state LF) printList
b: DummyLock;
1 @b.!state
[
g1: @b unlockGuard;
("released=" b.state LF) printList
] call
("relocked=" b.state LF) printList
0
] "main" exportFunction
Expected Output
locked=1
unlocked=0
released=0
relocked=1
See also
- windows/Mutex: SRW lock wrapper with exclusive and shared locking.
- Spinlock: Lightweight spinlock for concurrency control.
- windows/ConditionVariable: SRW-lock-based condition-variable wrapper.