silk.concurrency.fiber.
Fibers: handles to child tasks, with typed outcomes and one observer each.
When to use#
| Operation | Use it to |
|---|---|
forkChild | Start structured child work under the current Scheduler |
join | Wait for a child, and raise its failure in the current effect |
await | Wait for a child, and get success, failure or cancellation as data |
yieldNow | Let other ready tasks run before the current task continues |
Run the root program with silk.concurrency.local_scheduler, which provides the Scheduler service.
Details#
A Fiber has one completion observer. await and join consume the Fiber, so a Fiber
has at most one waiter. A successful fork publishes the complete child before it returns the
Fiber. The child body starts only when the scheduler drives it, not during the fork.
Completion, cancellation and yields notify an Execution with no allocation.
The other items (CompletionProducer, CompletionCanceller, PreparedFiber and the
completion functions) are for scheduler providers, not for application code.
Errors#
forkChildfails withOutOfMemoryErrororTaskIdExhaustedError.joinraises the typed failure of the child unchanged, orCancelled.
Gotchas#
Dropping a Fiber stops the observation. It does not cancel the task. The scheduler cancels unfinished children when the root finishes.
Examples#
Fork two children and join them#
import silk.mem.allocator { OutOfMemoryError }
import silk.core.effect { Effect }
import silk.concurrency.fiber { Cancelled, Fiber }
import silk.concurrency.local_scheduler { LocalScheduler, StalledError }
import silk.system.monotonic_clock { MonotonicClock }
import silk.system.monotonic_clock_native { OsMonotonicClock }
import silk.concurrency.scheduler { Scheduler, TaskIdExhaustedError }
effect fn square(value: i32) -> i32 {
// Lets the other ready task run first.
run Fiber.yieldNow()
return value * value
}
effect fn root() -> i32
! OutOfMemoryError | TaskIdExhaustedError | Cancelled
? &mut Scheduler | &mut MonotonicClock {
let three = run Fiber<i32, never>.forkChild(square(3))
let four = run Fiber<i32, never>.forkChild(square(4))
// join parks the root until the child finishes.
let first = run three.join()
let second = run four.join()
if first + second != 25 {
return 1
}
return 0
}
effect fn program() -> i32
! OutOfMemoryError | TaskIdExhaustedError | Cancelled | StalledError {
let mut clock = OsMonotonicClock.make()
let mut scheduler = LocalScheduler.make()
return run scheduler.execute<i32, OutOfMemoryError | TaskIdExhaustedError | Cancelled>(root())
|> Effect.provideMut<MonotonicClock>(&mut clock)
}
effect fn failed<E>(error: E) -> i32 {
drop error
return 1
}
pub fn main() -> i32 {
return run Effect.catchAll(program(), failed)
}Get a child failure as data#
import silk.mem.allocator { OutOfMemoryError }
import silk.core.effect { Effect }
import silk.concurrency.fiber { Failure, Fiber, Outcome }
import silk.concurrency.local_scheduler { LocalScheduler, StalledError }
import silk.system.monotonic_clock { MonotonicClock }
import silk.system.monotonic_clock_native { OsMonotonicClock }
import silk.concurrency.scheduler { Scheduler, TaskIdExhaustedError }
struct Invalid {
code: i32,
}
effect fn check(value: i32) -> i32
! Invalid {
if value < 0 {
fail Invalid { code: value }
}
return value
}
effect fn root() -> i32
! OutOfMemoryError | TaskIdExhaustedError
? &mut Scheduler | &mut MonotonicClock {
let child = run Fiber<i32, Invalid>.forkChild(check(-7))
// await gives the outcome as data. It does not raise the failure.
let outcome = run child.await()
let Outcome<i32, Invalid> { value } = move outcome
return match move value {
Failure<Invalid> { error } => {
if error.code != -7 {
return 1
}
return 0
}
_ => 1
}
}
effect fn program() -> i32
! OutOfMemoryError | TaskIdExhaustedError | StalledError {
let mut clock = OsMonotonicClock.make()
let mut scheduler = LocalScheduler.make()
return run scheduler.execute<i32, OutOfMemoryError | TaskIdExhaustedError>(root())
|> Effect.provideMut<MonotonicClock>(&mut clock)
}
effect fn failed<E>(error: E) -> i32 {
drop error
return 1
}
pub fn main() -> i32 {
return run Effect.catchAll(program(), failed)
}Import as Fiber with import silk.concurrency.fiber { Fiber }.
Public declarations: 8.
CompletionProducer#
pub struct CompletionProducer<A, E>The producer endpoint for one Fiber result.
Details#
A Scheduler provider owns this endpoint until it calls completeSuccess or
completeFailure. Both operations consume the endpoint and notify one parked observer.
CompletionCanceller#
pub struct CompletionCancellerThe type-erased cancellation endpoint for one Fiber result.
Details#
A task store can retain this endpoint without storing the Fiber success or failure types.
cancel consumes the endpoint and notifies one parked observer.
Fiber#
pub struct Fiber<A, E>An affine handle that observes one task result or cancellation.
When to use#
Get one from forkChild, which starts structured child work under the current Scheduler.
Use join to wait for the child and raise its failure in the current effect, or await to
get success, failure or cancellation as data. Run the root program with
silk.concurrency.local_scheduler, which provides the Scheduler service.
Details#
A Fiber has one completion observer. await and join consume the handle, so a Fiber has
at most one waiter. The child body starts only when the scheduler drives it, not during the
fork.
Gotchas#
Dropping the handle stops the observation. It does not cancel its task. The scheduler cancels unfinished children when the root finishes.
Implementation Fiber<A, E>#
impl<A, E> Fiber<A, E>Associated function prepare#
pub effect fn prepare() -> PreparedFiber<A, E>
! OutOfMemoryError
? &mut AllocatorAllocates the producer, canceller, and affine Fiber endpoints for one task.
When to use#
Use this provider operation before a Scheduler constructs and publishes a task.
Details#
No endpoint becomes visible until both Shared completion cells exist. Observation and notification allocate no further storage.
Associated function completeSuccess#
pub fn completeSuccess(producer: CompletionProducer<A, E>, value: A) -> ()Completes one Fiber with value and notifies its observer.
Details#
This operation stores value before it publishes readiness. It consumes the producer endpoint
and allocates no storage.
Associated function completeFailure#
pub fn completeFailure(producer: CompletionProducer<A, E>, error: E) -> ()Completes one Fiber with error and notifies its observer.
Details#
This operation stores error before it publishes readiness. It consumes the producer endpoint
and allocates no storage.
Associated function cancel#
pub fn cancel(canceller: CompletionCanceller) -> ()Publishes cancellation and notifies one parked Fiber observer.
Details#
This operation is independent of the Fiber success and failure types. It consumes the cancellation endpoint and allocates no storage.
Method await#
pub effect<'env> fn await<'env>(self: Self) -> Outcome<A, E>Consumes a Fiber and returns its success, typed failure, or cancellation as data.
Details#
A terminal Fiber returns immediately. A pending Fiber parks the current Execution and installs exactly one Wake. Observation and resumption allocate no storage.
Method join#
pub effect<'env> fn join<'env>(self: Self) -> A
! E | CancelledConsumes a Fiber, returns its success value, and propagates failure or cancellation.
Details#
A typed task failure is raised unchanged. Cancellation raises Cancelled. A pending Fiber
parks with the same allocation-free one-observer protocol as await.
Associated function yieldNow#
pub effect fn yieldNow() -> ()Relinquishes the current Execution once and immediately reports that it is ready.
When to use#
Use this operation to let tasks that are already ready run before the current task continues under a FIFO provider.
Details#
This operation consumes its Wake during registration. It needs no Scheduler service and allocates no storage. The provider selects the next activation order.
Outcome#
pub struct Outcome<A, E>The three possible terminal observations of a Fiber.
Field value#
pub value: Success<A> | Failure<E> | CancelledThe completed success, typed failure, or cancellation value.
Success#
pub struct Success<A>A successful Fiber outcome.
Field value#
pub value: AThe value returned by the task.
Failure#
pub struct Failure<E>A typed failed Fiber outcome.
Field error#
pub error: EThe error raised by the task.
Cancelled#
pub struct CancelledA Fiber outcome that reports structured task cancellation.
Implementation Debug for Cancelled#
impl Debug for CancelledOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites Cancelled.
PreparedFiber#
pub struct PreparedFiber<A, E>The three endpoints created for one future Fiber result.
Details#
A Scheduler provider gives fiber to the caller, captures producer in the task, and stores
canceller in its type-erased task entry.
Field producer#
pub producer: CompletionProducer<A, E>The endpoint that publishes a success or typed failure.
Field canceller#
pub canceller: CompletionCancellerThe type-erased endpoint that publishes cancellation.
Field fiber#
pub fiber: Fiber<A, E>The affine result handle returned after task publication succeeds.
Implementation Fiber<A, E>#
impl<A: 'static, E: 'static> Fiber<A, E>Associated function forkChild#
pub effect fn forkChild(
child: once Effect<'static;
A
! E
? &mut Scheduler | &mut MonotonicClock
>
) -> Fiber<A, E>
! OutOfMemoryError | TaskIdExhaustedError
? &mut SchedulerPrepares and atomically publishes one child task, then returns its affine Fiber.
When to use#
Use this operation to run closed work or work that uses the child Scheduler and MonotonicClock providers.
Details#
Preparation finishes its exclusive Scheduler dispatch before publication starts. Publication returns the Fiber only after the provider accepts the complete child. The provider records that acceptance and wakes the parent before it notifies the child's initial readiness. The child body starts only when the Scheduler later drives it.
Gotchas#
Allocation refusal or task-identity exhaustion raises the exact preparation failure:
OutOfMemoryError or TaskIdExhaustedError. Publication refusal raises OutOfMemoryError,
returns no Fiber, and does not activate the child. Dropping the Fiber does not cancel the
child. The scheduler cancels unfinished children when the root finishes.
Category: Concurrency.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.