mirror of
https://github.com/justinethier/cyclone.git
synced 2025-07-15 08:47:35 +02:00
Major revisions
This commit is contained in:
parent
5473fa7135
commit
8571b7526d
1 changed files with 16 additions and 18 deletions
|
@ -2,7 +2,7 @@
|
|||
|
||||
The `(cyclone concurrent)` library provides functions to make it easier to write concurrent programs.
|
||||
|
||||
TODO: explain relationship to SRFI 18
|
||||
This library complements the functionality provided by [SRFI 18](../srfi/18.md).
|
||||
|
||||
## Index
|
||||
|
||||
|
@ -18,19 +18,19 @@ TODO: explain relationship to SRFI 18
|
|||
|
||||
## Shared Objects
|
||||
|
||||
Cyclone allocates most new objects in a thread-local stack. This is efficient for single-threaded code but causes problems when an object must be used by multiple threads. An object on another thread's stack could be overwritten or moved at any time, leading to undefined behavior.
|
||||
Cyclone allocates new objects using the current thread's local stack. This is efficient for single-threaded code but causes problems when an object must be used by other threads. An object on another thread's stack could be overwritten or moved at any time, leading to undefined behavior. The solution is Shared Objects. A shared object is an object located in a section of memory available for use by any thread.
|
||||
|
||||
Cyclone deals with this problem using the concept of Shared Objects. A shared object is an object located in a segment of memory that is available for use by any thread. Note that concurrency primitives must still be used to safely coordinate access to these objects!
|
||||
Note that concurrency primitives must still be used to safely coordinate access to shared objects!
|
||||
|
||||
The following types of objects are always shared:
|
||||
|
||||
- Concurrency primitives (mutex, conditional variable, atom). These object are allocated on the heap since the intent is for multiple threads to use them for synchronization.
|
||||
- Concurrency primitives (mutex, conditional variable, atom). These object are allocated directly on the heap since by definition multiple threads need to use them for synchronization.
|
||||
|
||||
- Fixnum integers and characters. These are immediates (IE, value types) so there is no object reference.
|
||||
- Fixnum integers and characters. These are immediates (IE, value types) so there is no object in memory to reference.
|
||||
|
||||
- Booleans, bignums, symbols, and the EOF object.
|
||||
|
||||
All other objects must be shared before they can be safely used by multiple threads.
|
||||
All other objects must be explicitly shared before they can be safely used by multiple threads.
|
||||
|
||||
### make-shared
|
||||
|
||||
|
@ -52,7 +52,9 @@ Note this function will trigger a minor garbage collection on the calling thread
|
|||
|
||||
## Immutable objects
|
||||
|
||||
Many types of objects are mutable by default: pairs, strings, vectors, and bytevectors. However, if an object is declared as a literal constant then it will be designated immutable. The easiest way to do this is to use a single-quote, EG:
|
||||
Many types of objects are mutable by default: pairs, strings, vectors, and bytevectors. However, if an object is declared as a literal constant then it will be designated immutable.
|
||||
|
||||
The easiest way to do this is to use a single-quote, EG:
|
||||
|
||||
cyclone> (import (cyclone concurrent))
|
||||
ok
|
||||
|
@ -62,9 +64,10 @@ Many types of objects are mutable by default: pairs, strings, vectors, and bytev
|
|||
cyclone> (immutable? my-lis)
|
||||
#t
|
||||
|
||||
It is an error to attempt to call a mutation procedure (such as `set-car!` or `string-set!`) on an immutable object.
|
||||
It is an error to call a mutation procedure (such as `set-car!` or `string-set!`) on an immutable object.
|
||||
|
||||
### immutable?
|
||||
|
||||
(immutable? obj)
|
||||
|
||||
Predicate that returns `#t` if `obj` is immutable and `#f` otherwise.
|
||||
|
@ -83,11 +86,12 @@ For example:
|
|||
ok
|
||||
cyclone> (make-atom (list 1 2))
|
||||
Error: Expected immutable object : (1 2)
|
||||
cyclone> (make-atom (make-shared (list 1 2)))
|
||||
Error: Expected immutable object : (1 2)
|
||||
cyclone> (make-atom (make-shared '(1 2)))
|
||||
<atom 0x7f742b99bb00>
|
||||
|
||||
Example programs:
|
||||
|
||||
- Summing numbers using atomic operations: [`sum-atomic.scm`](../../../examples/threading/sum-atomic.scm)
|
||||
|
||||
TODO: link to sum examples
|
||||
TODO: memoization example?
|
||||
|
@ -115,9 +119,9 @@ Type predicate, returns `#t` if `obj` is an atom and `#f` otherwise.
|
|||
|
||||
### deref
|
||||
|
||||
(deref atm)
|
||||
(deref atom)
|
||||
|
||||
Dereference an atom by returning its current value.
|
||||
Dereference; returns the current value of `atom`.
|
||||
|
||||
### swap!
|
||||
|
||||
|
@ -131,12 +135,6 @@ Note that `f` may be called multiple times and thus should be free of side effec
|
|||
|
||||
Based on the procedure of the same name from Clojure.
|
||||
|
||||
;; Notes:
|
||||
;; swap! takes the current value of the Atom, calls the function on it (in this case, inc), and sets the new value. However, just before setting the new value, it checks to make sure the old value is still in there. If it's different, it starts over. It calls the function again with the new value it found. It keeps doing this until it finally writes the value. Because it can check the value and write it in one go, it's an atomic operation, hence the name.
|
||||
;;
|
||||
;; That means the function can get called multiple times. That means it needs to be a pure function. Another thing is that you can't control the order of the function calls. If multiple threads are swapping to an Atom at the same time, order is out of the window. So make sure your functions are independent of order, like we talked about before.
|
||||
;;
|
||||
|
||||
### compare-and-set!
|
||||
|
||||
(compare-and-set! atom oldval newval)
|
||||
|
|
Loading…
Add table
Reference in a new issue