@@ -120,21 +120,17 @@ val x : int Loc.t = <abstr>
120120One can then manipulate the locations individually:
121121
122122``` ocaml
123- # Loc.set a 6
123+ # Loc.set a 10
124124- : unit = ()
125125
126126# Loc.get a
127- - : int = 6
128- ```
129-
130- Attempt primitive operations over multiple locations:
127+ - : int = 10
131128
132- ``` ocaml
133- # Op.atomically [
134- Op.make_cas a 6 10;
135- Op.make_cas b 0 52
136- ]
129+ # Loc.compare_and_set b 0 52
137130- : bool = true
131+
132+ # Loc.get b
133+ - : int = 52
138134```
139135
140136Block waiting for changes to locations:
@@ -170,16 +166,12 @@ And now we have it:
170166The API of ** Kcas** is divided into submodules. The main modules are
171167
172168- [ ` Loc ` ] ( https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Loc/index.html ) ,
173- providing an abstraction of _ shared memory locations_ ,
169+ providing an abstraction of _ shared memory locations_ , and
174170
175171- [ ` Xt ` ] ( https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Xt/index.html ) ,
176- providing _ explicit transaction log passing_ over shared memory locations, and
177-
178- - [ ` Op ` ] ( https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Op/index.html ) ,
179- providing an interface for _ primitive operations_ over multiple shared memory
180- locations.
172+ providing _ explicit transaction log passing_ over shared memory locations.
181173
182- The following sections discuss each of the above in turn.
174+ The following sections discuss both of the above in turn.
183175
184176### Creating and manipulating individual shared memory locations
185177
@@ -192,9 +184,7 @@ In other words, an application that uses
192184[ ` Atomic ` ] ( https://v2.ocaml.org/api/Atomic.html ) , but then needs to perform
193185atomic operations over multiple atomic locations, could theoretically just
194186rebind ` module Atomic = Loc ` and then use the
195- [ ` Op ` ] ( https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Op/index.html ) ,
196- and/or
197- [ ` Xt ` ] ( https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Xt/index.html ) APIs
187+ [ ` Xt ` ] ( https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Xt/index.html ) API
198188to perform operations over multiple locations. This should not be done
199189just-in-case, however, as, even though ** Kcas** is efficient, it does naturally
200190have higher overhead than the Stdlib
@@ -449,10 +439,8 @@ val a_queue : int queue = {front = <abstr>; back = <abstr>}
449439
450440#### Composing transactions
451441
452- The main benefit of the
442+ The main feature of the
453443[ ` Xt ` ] ( https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Xt/index.html ) API
454- over the
455- [ ` Op ` ] ( https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Op/index.html ) API
456444is that transactions are composable. In fact, we already wrote transactions that
457445recorded multiple primitive shared memory accesses to the explicitly passed
458446transaction log. Nothing prevents us from writing transactions calling other
@@ -1049,72 +1037,6 @@ val a_cache : (int, string) cache =
10491037As an exercise, implement an operation to ` remove ` associations from a cache and
10501038an operation to change the capacity of the cache.
10511039
1052- ### Programming with primitive operations
1053-
1054- In addition to the transactional interface, ** Kcas** also provides the
1055- [ ` Op ` ] ( https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Op/index.html )
1056- interface for performing a list of primitive operations. To program with
1057- primitive operations one simply makes a list of CAS operations using
1058- [ ` make_cas ` ] ( https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Op/index.html#val-make_cas )
1059- and then attempts them using
1060- [ ` atomically ` ] ( https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Op/index.html#val-atomically ) .
1061- Typically that needs to be done inside a loop of some kind as such an attempt
1062- can naturally fail.
1063-
1064- Let's first
1065- [ ` make ` ] ( https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Loc/index.html#val-make )
1066- two locations representing stacks:
1067-
1068- ``` ocaml
1069- # let stack_a = Loc.make [19]
1070- and stack_b = Loc.make [76]
1071- val stack_a : int list Loc.t = <abstr>
1072- val stack_b : int list Loc.t = <abstr>
1073- ```
1074-
1075- Here is a function that can atomically move an element from given ` source ` stack
1076- to the given ` target ` stack:
1077-
1078- ``` ocaml
1079- # let rec move ?(backoff = Backoff.default)
1080- source
1081- target =
1082- match Loc.get source with
1083- | [] -> raise Exit
1084- | (elem::rest) as old_source ->
1085- let old_target = Loc.get target in
1086- let ops = [
1087- Op.make_cas source old_source rest;
1088- Op.make_cas target old_target (elem::old_target)
1089- ] in
1090- if not (Op.atomically ops) then
1091- let backoff = Backoff.once backoff in
1092- move ~backoff source target
1093- val move : ?backoff:Backoff.t -> 'a list Loc.t -> 'a list Loc.t -> unit =
1094- <fun>
1095- ```
1096-
1097- Note that we also used the
1098- [ ` Backoff ` ] ( https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Backoff/index.html )
1099- module provided by ** Kcas** above.
1100-
1101- Now we can simply call ` move ` :
1102-
1103- ``` ocaml
1104- # move stack_a stack_b
1105- - : unit = ()
1106-
1107- # Loc.get stack_a
1108- - : int list = []
1109-
1110- # Loc.get stack_b
1111- - : int list = [19; 76]
1112- ```
1113-
1114- As one can see, the API provided by
1115- [ ` Op ` ] ( https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Op/index.html ) is
1116- quite low-level and is not intended for application level programming.
1117-
11181040## Designing lock-free algorithms with k-CAS
11191041
11201042The key benefit of k-CAS, or k-CAS-n-CMP, and transactions in particular, is
0 commit comments