Under heavy development. This site describes the intended 1.0 language. Current features and performance vary. Development status
Sn50SnThe SnAPI programming language
Development · Evolving reference

AsyncMutex

Owns retained payload with suspension-backed exclusive acquisition. LockAsync does not block a worker while awaiting ownership. Guards can cross await and have no native-thread unlock affinity. Recursive acquisition can deadlock; no fairness or starvation bound is promised. Published readonly owner borrows may acquire concurrently; moving the owner needs synchronization. Guards/wait leases retain state independently of visible owner cleanup.

Sn is under heavy development. This reference includes the intended 1.0 design; features may be incomplete in the current compiler. Read the status →

Module std.sync

import std.sync;

Public declaration contracts and authored examples. A page can document several related symbols. Implementation bodies are excluded.

AsyncMutex

pub final class AsyncMutex<T> where T: Movable

Owns retained payload with suspension-backed exclusive acquisition. LockAsync does not block a worker while awaiting ownership. Guards can cross await and have no native-thread unlock affinity. Recursive acquisition can deadlock; no fairness or starvation bound is promised. Published readonly owner borrows may acquire concurrently; moving the owner needs synchronization. Guards/wait leases retain state independently of visible owner cleanup. T: Movable protected payload.

Example

module example.async_mutex;
from std.sync import AsyncMutex, AsyncMutexGuard;
from std.task import Task, YieldAsync;
async fn Main() -> Task<i32> {
    let Owner = {
        // Keep writable result storage through the explicit noncopy payload transfer.
        var OwnerCreation = AsyncMutex<i32>.TryCreate(40);
        switch OwnerCreation {
            case .Ok { Value = CreatedOwner: mut AsyncMutex<i32>& } => break move(CreatedOwner);
            case .Err { Error = Error } => { if Error.Value != 40 { return 2; } return 1; }
        }
    };
    {
        var Guard = {
            // Keep writable result storage through the explicit noncopy payload transfer.
            var GuardCreation = await Owner.LockAsync();
            switch GuardCreation {
                case .Ok { Value = AcquiredGuard: mut AsyncMutexGuard<i32>& } => break move(AcquiredGuard);
                case .Err => return 3;
            }
        };
        Guard.Value() += 2;
        switch await YieldAsync() { case .Ok => {} case .Err => return 4; }
        let Readonly: readonly AsyncMutexGuard<i32>& = Guard;
        if Readonly.Value() != 42 { return 5; }
        switch Owner.TryLock() {
            case .Ok { Value = Value } => { if Value is .Some { Value = _ } { return 6; } }
            case .Err => return 7;
        }
    }
    // The writable wrapper owns the optional guard through its transfer.
    var LockAttempt = Owner.TryLock();
    switch LockAttempt {
        case .Ok { Value = Value: mut AsyncMutexGuard<i32>?& } => {
            switch move(Value) { case .Some { Value = Guard } => { if Guard.Value() != 42 { return 8; } } case .None => return 9; }
        }
        case .Err => return 10;
    }
    return 0;
}

AsyncMutex.init

pub init()

Creates empty owner without allocating.

AsyncMutex.init

pub init(Source: readonly Self&) = delete;

Rejects duplicate visible owner authority. Source: Existing owner.

AsyncMutex.init

pub init(Source: mut Self&&)

Transfers visible ownership; guards keep independent storage. Source: Owner left inert.

AsyncMutex.operator

pub fn operator =(Source: readonly Self&) -> void = delete;

Rejects duplicate visible owner authority. Source: Existing owner. Return: No runtime result; this assignment is deleted and cannot be invoked.

AsyncMutex.operator

pub fn operator =(Source: mut Self&&) -> void

Releases previous visible state without waiting and transfers Source. Source: Owner left inert; exact self-move uses shared transport. Return: No value after transferring shared state and releasing displaced visible ownership without waiting.

AsyncMutex.IsEmpty

pub IsEmpty: bool;

Reports default/moved visible ownership.

AsyncMutex.TryCreate

pub static fn TryCreate(mut Value: T) -> Result<Self, AsyncMutexCreationError<T>>

Allocates permit/shared storage, preserving input on every expected failure. Value: Owned protected payload, returned with any creation error. Return: Owner or typed creation failure retaining Value.

AsyncMutex.LockAsync

pub readonly async fn LockAsync(mut Token: CancellationToken) -> Task<Result<AsyncMutexGuard<T>, AsyncMutexError>>

Suspends on permit ownership without occupying a worker while pending. Token: Owned retained cancellation observation, inert by default. Return: Retained exclusive guard or exact portable permit/cancellation error.

AsyncMutex.LockAsync

pub readonly fn LockAsync() -> Task<Result<AsyncMutexGuard<T>, AsyncMutexError>>

Supplies the omitted arguments to LockAsync. Note: Defaults: Token = CancellationToken(). Return: Exact full-operation result; no additional async frame is created.

AsyncMutex.TryLock

pub readonly fn TryLock() -> Result<AsyncMutexGuard<T>?, AsyncMutexError>

Attempts ownership without waiting for another guard to release. Return: Optional retained guard, empty on contention, or portable error.

Documentation snapshot: October 24, 2026 About versions ↗
Searching Development · language & standard library