forked from MightyPork/crsn
document coroutines
This commit is contained in:
@@ -286,7 +286,77 @@ It can also be written like this:
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
## Coroutines
|
||||
|
||||
Croissant implements something that could be called "pre-emptive coroutines". They do not provide any performance gain,
|
||||
but add asynchronicity to the program, and can work as generators!
|
||||
|
||||
There is no true parallelism, it is difficult to implement safely and efficiently with a global state.
|
||||
|
||||
### Spawning
|
||||
|
||||
*Any procedure can be used as a coroutine.*
|
||||
|
||||
A coroutine is created using the `spawn` instruction, which produces an object handle.
|
||||
|
||||
```
|
||||
(spawn r0 do_stuff 1 2 3)
|
||||
```
|
||||
|
||||
At this point, the program is evenly divided between the original and the coroutine "thread".
|
||||
|
||||
The spawned coroutine is scheduled to run immediately after being spawned.
|
||||
|
||||
### Task switching
|
||||
|
||||
Coroutines take turns to execute the program. The scheduling interval can be configured.
|
||||
|
||||
Control can be given up using the `yield` instruction; for example, when waiting for a mutex. This happens automatically when
|
||||
a `sleep` instruction is invoked.
|
||||
|
||||
### Race conditions
|
||||
|
||||
Take care when working with objects, resources and global registers: you can get race conditions
|
||||
with coroutines. Use atomic instructions (`cas`, `casXX`, `bfcas`…) to implement synchronization.
|
||||
|
||||
The `casXX` instruction is very powerful: you can use one bit of a register as a mutex and the rest of it to store some useful data.
|
||||
You can also use one register for up to 64 mutexes.
|
||||
|
||||
Remember to only use global registers (or buffer items) as mutexes: `g0`-`g15`. Each coroutine has its own set of *regular* registers.
|
||||
|
||||
### Using coroutines as generators
|
||||
|
||||
A coroutine can "yield a value" by invoking the `yield` instruction with an operand. This can be done any number of times.
|
||||
|
||||
```
|
||||
(yield r0)
|
||||
```
|
||||
|
||||
The coroutine is blocked until the value is consumed by someone. To consume a yielded value, read the coroutine object handle:
|
||||
|
||||
```
|
||||
(spawn r5 foo)
|
||||
|
||||
(ld r0 @r5) ; read a yielded value
|
||||
```
|
||||
|
||||
### Joining a coroutine
|
||||
|
||||
Use the `join` instruction with a coroutine object handle to wait for its completion.
|
||||
|
||||
A coroutine completes by calling `ret` at its top level. This naturally means that a coroutine can return values!
|
||||
|
||||
The returned values are placed in the result registers, just like with the `call` instruction.
|
||||
|
||||
```
|
||||
(spawn r5 foo)
|
||||
; ...
|
||||
|
||||
(join @r0)
|
||||
; res0-res15 now contain return values
|
||||
```
|
||||
|
||||
# Instruction Set
|
||||
|
||||
Crsn instruction set is composed of extensions.
|
||||
|
||||
Reference in New Issue
Block a user