Under heavy development. This site describes the intended 1.0 language. Current features and performance vary. Development status
Sn50SnThe SnAPI programming language
0.2.0 Preview 1 · Frozen documentation

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. Reference extracted from this release’s bundled standard library. Public API examples are not an exhaustive compatibility test. Read the matching release guide for tested workflows and limitations. 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