- Loading...
...
fiber1 is scheduled in scope1 to execute foo. It enters scope2 and schedules two fibers. It exits scope2 (and returns to scope1) when the two fibers terminate. fiber2 is scheduled in scope1 to execute bar. It enters scope3 and schedules two fibers. It exits scope3 (and returns to scope1) when the two fibers terminate. The thread or fiber executing will not exit scope1 until fiber1 and fiber2 have terminated.
As an escape hatch, the FiberScope API also defines the static background() method to return the background scope which can be used to schedule fibers that are intended to outline the context where they are initially scheduled.
A fiber executing in cancellable scope may be cancelled by invoking its cancel method to set the fiber’s cancel status and unpark the fiber. Cancellation works cooperatively: a Fiber needs to check for cancellation (say, when doing blocking operations), and throw an appropriate exception for the context that it is running in (which might be an InterruptedException in methods that throw this exception, an IOException or sub-class when in a method that does I/O).
At this time, the following blocking operations wakeup and throw an exception when the fiber is cancelled:
FiberScope can be created with options that configure how cancellation is handled. At this time, the options are PROPAGATE_CANCEL, CANCEL_AT_CLOSE, and IGNORE_CANCEL.
The following example uses the PROPAGATE_CANCEL option:
| Code Block | ||
|---|---|---|
| ||
try (var scope = FiberScope.open(Option.PROPAGTE_CANCEL)) {
var fiber1 = scope.schedule(task);
var fiber2 = scope.schedule(task);
} |
If a fiber executing in this scope is cancelled then it will also cancel fiber1 and fiber2There are rare, but important, cases such as shutdown or recovery steps where a fiber may need to be shielded from cancellation. To support this, FiberScope defines the nonCancellable() method to enter a non-cancellable scope. A Fiber that checks for cancellation in a non-cancellation scope will get back “false”. If its cancel status is set then it will observe this when it pops back to a cancellable scope.
Decomposing deadline or timeouts is very difficult to get right.
...
FiberScope also defines open(Duration timeout) to enter a scope with a timeout. If the timeout expires before thread/fiber exits the scope then all fibers scheduled in the scope are cancelled.
Further reading:
Nathaniel J. Smith: Notes on structured concurrency, or: Go statement considered harmful
Nathaniel J. Smith: Timeouts and cancellation for humans
Martin Sustrik: Structured Concurrency
There is no support at this time for making context available to all fibers scheduled in the scope. InheritedThreadLocals can be used in the mean-time.
The current FiberScope API is a prototype API to demonstrate and explore concepts. For now, FiberScope is an AutoCloseable and so encourages the use of the try-with-resources construct. The advantages of this approach is that it plays well with checked exceptions and it is easy to access variables in the enclosing scope. The downside is lack of guaranteed cleanup (a ThreadDeath, OOME, or other resource issues may abort the execution of the finally block and close). It is also possible to misuse, e.g. leak the scope to a callee that closes it explicitly. An alternative API that has also been prototyped
| Code Block | ||
|---|---|---|
| ||
FiberScope.cancellable(scope -> { ... }); |
Nathaniel J. Smith: Notes on structured concurrency, or: Go statement considered harmful
Nathaniel J. Smith: Timeouts and cancellation for humans
Martin Sustrik: Structured Concurrency
...
...