Atomic updates: Difference between revisions

m
m (→‎{{header|Phix}}: added syntax colouring, marked p2js incompatible)
m (→‎{{header|Wren}}: Minor tidy)
 
(6 intermediate revisions by 3 users not shown)
Line 23:
 
=={{header|8th}}==
<langsyntaxhighlight Forthlang="forth">var bucket
var bucket-size
 
Line 115:
\ the print-the-bucket task. We'll do it just 10 times and then quit:
( 1 sleep .bucket ) 10 times
bye ;</langsyntaxhighlight>
{{out}}<pre>[941,654,311,605,332,822,62,658,9,348] 4742
[289,98,710,698,183,490,675,688,793,118] 4742
Line 130:
 
=={{header|Ada}}==
<langsyntaxhighlight lang="ada">with Ada.Text_IO; use Ada.Text_IO;
with Ada.Numerics.Discrete_Random;
Line 214:
end;
end loop;
end Test_Updates;</langsyntaxhighlight>
The array of buckets is a protected object which controls access to its state. The task Equalize averages pairs of buckets. The task Mess_Up moves content of one bucket to another. The main task performs monitoring of the buckets state. Sample output:
<pre>
Line 231:
 
=={{header|AutoHotkey}}==
<langsyntaxhighlight AutoHotkeylang="autohotkey">Bucket := [], Buckets := 10, Originaltotal = 0
loop, %Buckets% {
Random, rnd, 0,50
Line 271:
Res.= ">"
return Res
}</langsyntaxhighlight>
 
=={{header|BBC BASIC}}==
{{works with|BBC BASIC for Windows}}
The BBC BASIC interpreter is single-threaded so the 'concurrent' tasks are implemented by timer events. In this context an 'atomic' update means one which takes place within a single BASIC statement, so it cannot be 'interrupted'. Two (or more) buckets can be updated atomically by making them RETURN parameters of a procedure.
<langsyntaxhighlight lang="bbcbasic"> INSTALL @lib$+"TIMERLIB"
DIM Buckets%(100)
Line 327:
PROC_killtimer(tid1%)
PROC_killtimer(tid2%)
ENDPROC</langsyntaxhighlight>
 
=={{header|C}}==
Line 335:
 
{{libheader|pthread}}
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
Line 445:
for(i=0; i < N_BUCKETS; i++) pthread_mutex_destroy(bucket_mutex+i);
return EXIT_SUCCESS;
}</langsyntaxhighlight>
 
===With OpenMP===
Compiled with <code>gcc -std=c99 -fopenmp</code>. The <code>#pragma omp critical</code> ensures the following block is entered by one thread at a time.
<langsyntaxhighlight Clang="c">#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
Line 499:
 
return 0;
}</langsyntaxhighlight>Output:<syntaxhighlight lang="text">1000 1000 1000 1798 1000 1000 1000 1000 202 1000 Sum: 10000
595 800 2508 2750 470 1209 283 314 601 470 Sum: 10000
5 521 3339 1656 351 1038 1656 54 508 872 Sum: 10000
Line 506:
.
752 490 385 2118 1503 508 384 509 1110 2241 Sum: 10000
752 823 385 2118 1544 508 10 509 1110 2241 Sum: 10000</langsyntaxhighlight>
 
=={{header|C sharp|C#}}==
This C# implementation uses a class to hold the buckets and data associated with them. The ThreadSafeBuckets class implements thread-stability, and ensures that two threads cannot operate on the same data at the same time. Additionally, the class uses a seperate mutex for each bucket, allowing multiple operations to occur at once if they do not alter the same buckets.
 
Line 515:
- The previous implementation tracked a "swapped" state - which seems a harder way to tackle the problem. You need to acquire the locks in the correct order, not swap i and j
 
<langsyntaxhighlight lang="csharp">
using System; //Rand class
using System.Threading; //Thread, Mutex classes
Line 640:
}
}
}</langsyntaxhighlight>
 
Sample Output:
Line 657:
 
{{works with|C++11}}
<langsyntaxhighlight lang="cpp">#include <algorithm>
#include <array>
#include <chrono>
Line 748:
}
return 0;
}</langsyntaxhighlight>
 
=={{header|Clojure}}==
Function returning a new map containing altered values:
<langsyntaxhighlight lang="lisp">(defn xfer [m from to amt]
(let [{f-bal from t-bal to} m
f-bal (- f-bal amt)
Line 758:
(if (or (neg? f-bal) (neg? t-bal))
(throw (IllegalArgumentException. "Call results in negative balance."))
(assoc m from f-bal to t-bal))))</langsyntaxhighlight>
Since clojure data structures are immutable, atomic mutability occurs via a reference, in this case an atom:
<langsyntaxhighlight lang="lisp">(def *data* (atom {:a 100 :b 100})) ;; *data* is an atom holding a map
(swap! *data* xfer :a :b 50) ;; atomically results in *data* holding {:a 50 :b 150}</langsyntaxhighlight>
Now for the test:
<langsyntaxhighlight lang="lisp">(defn equalize [m a b]
(let [{a-val a b-val b} m
diff (- a-val b-val)
Line 784:
 
(.start thread-eq)
(.start thread-rand)</langsyntaxhighlight>
 
=={{header|Common Lisp}}==
Depends on libraries in Quicklisp. STMX is a library that provides Software Transactional Memory.
<langsyntaxhighlight lang="lisp">(ql:quickload '(:alexandria :stmx :bordeaux-threads))
 
(defpackage :atomic-updates
Line 824:
(setf *running* t)
(bt:make-thread (lambda () (runner (constantly 0.5))))
(bt:make-thread (lambda () (runner (lambda () (random 1.0))))))</langsyntaxhighlight>
{{out}}
<langsyntaxhighlight lang="lisp">ATOMIC-UPDATES> (scenario)
#<SB-THREAD:THREAD "Anonymous thread" RUNNING {10058441D3}>
ATOMIC-UPDATES> (loop repeat 3 do (print-buckets) (sleep 1))
Line 835:
Buckets: #(1 2 3 3 2 8 33 23 0 8 4 11 24 2 3 5 32 8 2 26)
Sum: 200
NIL</langsyntaxhighlight>
 
=={{header|D}}==
This implements a more scalable version than most of the other languages, by using a lock per bucket instead of a single lock for the whole array.
 
<langsyntaxhighlight lang="d">import std.stdio: writeln;
import std.conv: text;
import std.random: uniform, Xorshift;
Line 955:
task!equalize(data).executeInNewThread();
task!display(data).executeInNewThread();
}</langsyntaxhighlight>
{{out}}
<pre>N. transfers, buckets, buckets sum:
Line 981:
This example uses a Java AWT window to display the current state of the buckets.
 
<langsyntaxhighlight lang="e">#!/usr/bin/env rune
pragma.syntax("0.9")
 
Line 1,103:
 
frame.show()
interp.waitAtTop(done)</langsyntaxhighlight>
 
=={{header|Erlang}}==
Line 1,120:
[0,11,7,0,4,16,7,0,10,0] = 55
</pre>
<syntaxhighlight lang="erlang">
<lang Erlang>
-module( atomic_updates ).
-export( [buckets/1, buckets_get/2, buckets_get_all/1, buckets_move_contents/4, task/0] ).
Line 1,209:
buckets_move_contents( Amount, From, To, Buckets ),
redistribute_loop( N, Buckets ).
</syntaxhighlight>
</lang>
 
=={{header|Euphoria}}==
<langsyntaxhighlight lang="euphoria">function move(sequence s, integer amount, integer src, integer dest)
if src < 1 or src > length(s) or dest < 1 or dest > length(s) or amount < 0 then
return -1
Line 1,280:
printf(1," sum: %d\n", {sum(buckets)})
task_yield()
end for</langsyntaxhighlight>
 
Output:
Line 1,313:
The Buckets class is thread safe and its private higher-order Lock function ensures that locks are taken out in order (to avoid deadlocks):
 
<langsyntaxhighlight lang="fsharp">
open System.Threading
 
Line 1,387:
Thread.Sleep 100
bucket.Print()
</syntaxhighlight>
</lang>
 
This program performs a million concurrent transfers. Typical output is:
 
<langsyntaxhighlight lang="fsharp">
[|100; 100; 100; 100; 100; 100; 100; 100; 100; 100|] = 1000
[|119; 61; 138; 115; 157; 54; 82; 58; 157; 59|] = 1000
Line 1,450:
[|208; 147; 18; 25; 178; 159; 23; 170; 36; 36|] = 1000
Press any key to continue . . .
</syntaxhighlight>
</lang>
 
=={{header|FreeBASIC}}==
{{trans|Run Basic}}
<syntaxhighlight lang="freebasic">Randomize Timer
Dim Shared As Uinteger cubo(1 To 10), a, i
For i As Uinteger = 1 To 10
cubo(i) = Int(Rnd * 90)
Next i
 
Function Display(cadena As String) As Uinteger
Dim As Uinteger valor
Print cadena; Spc(2);
For i As Uinteger = 1 To 10
valor += cubo(i)
Print Using "###"; cubo(i);
Next i
Print " Total:"; valor
Return valor
End Function
 
Sub Flatten(f As Uinteger)
Dim As Uinteger f1 = Int((f / 10) + .5), f2
For i As Uinteger = 1 To 10
cubo(i) = f1
f2 += f1
Next i
cubo(10) += f - f2
End Sub
 
Sub Transfer(a1 As Uinteger, a2 As Uinteger)
Dim As Uinteger temp = Int(Rnd * cubo(a1))
cubo(a1) -= temp
cubo(a2) += temp
End Sub
 
a = Display(" Display:") ' show original array
Flatten(a) ' flatten the array
a = Display(" Flatten:") ' show flattened array
Transfer(3, 5) ' transfer some amount from 3 to 5
Display(" 19 from 3 to 5:") ' show transfer array
Sleep</syntaxhighlight>
{{out}}
<pre> Display: 8 77 51 38 76 47 43 16 1 1 Total: 358
Flatten: 36 36 36 36 36 36 36 36 36 34 Total: 358
19 from 3 to 5: 36 36 21 36 51 36 36 36 36 34 Total: 358</pre>
 
=={{header|FutureBasic}}==
<syntaxhighlight lang="futurebasic">
local fn PopulateArrayWithRandomNumbers
NSUInteger i
for i = 0 to 9
mda (i) = rnd(90)
next
end fn
 
local fn Display( title as CFStringRef ) as NSUInteger
NSUInteger i, worth = 0
CFStringRef comma = @","
printf @"%@ [\b", title
for i = 0 to 9
worth += mda_integer (i)
if i == 9 then comma = @""
printf @"%2lu%@\b", mda_integer (i), comma
next
printf @"] Sum = %lu", worth
end fn = worth
 
local fn Flatten( f as NSUInteger )
NSUInteger i, f1 = int((f / 10) + .5 ), f2 = 0, temp
for i = 0 to 9
mda (i) = f1
f2 += f1
next
temp = mda_integer (9)
mda (9) = temp + f - f2
end fn
 
local fn Transfer( a1 as NSUInteger, a2 as NSUInteger )
NSUInteger t, temp = int( rnd( mda_integer ( a1 ) ) )
t = mda_integer ( a1 ) : mda ( a1 ) = t -temp
t = mda_integer ( a2 ) : mda ( a2 ) = t +temp
end fn
 
NSUInteger a, i
 
random
fn PopulateArrayWithRandomNumbers
a = fn Display( @" Initial array:" )
fn Flatten( a )
a = fn Display( @" Current values:" )
fn Transfer( 3, 5 )
fn Display( @" 19 from 3 to 5:" )
 
HandleEvents
</syntaxhighlight>
{{output}}
<pre>
Initial array: [28,73,90, 1,75,51,69,35,70,28] Sum = 520
Current values: [52,52,52,52,52,52,52,52,52,52] Sum = 520
19 from 3 to 5: [52,52,52,34,52,70,52,52,52,52] Sum = 520
</pre>
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 1,602 ⟶ 1,707:
}
}
}</langsyntaxhighlight>
{{out}}
<pre>
Line 1,616 ⟶ 1,721:
=={{header|Groovy}}==
Solution:
<langsyntaxhighlight lang="groovy">class Buckets {
 
def cells = []
Line 1,694 ⟶ 1,799:
}
Thread.sleep(500)
}</langsyntaxhighlight>
 
Output:
Line 1,726 ⟶ 1,831:
So, at any given time, the current value map is either in the MVar or being examined or replaced by one thread, but not both. The IntMap held by the MVar is a pure immutable data structure (<code>adjust</code> returns a modified version), so there is no problem from that the ''display'' task puts the value back before it is done printing.
 
<langsyntaxhighlight lang="haskell">module AtomicUpdates (main) where
 
import Control.Concurrent (forkIO, threadDelay)
Line 1,794 ⟶ 1,899:
forkIO (roughen buckets)
forkIO (smooth buckets)
display buckets</langsyntaxhighlight>
 
Sample output:
Line 1,816 ⟶ 1,921:
The following only works in Unicon:
 
<langsyntaxhighlight lang="unicon">global mtx
 
procedure main(A)
Line 1,848 ⟶ 1,953:
buckets[b1] -:= x
buckets[b2] +:= x
end</langsyntaxhighlight>
 
Sample run:
Line 1,869 ⟶ 1,974:
=={{header|Java}}==
{{works with|Java|8+}}
<langsyntaxhighlight lang="java">import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom;
 
Line 1,974 ⟶ 2,079:
}
}
}</langsyntaxhighlight>
 
{{out}}
Line 1,992 ⟶ 2,097:
 
=={{header|Julia}}==
<langsyntaxhighlight lang="julia">using StatsBase
 
function runall()
Line 2,051 ⟶ 2,156:
end
 
runall()</langsyntaxhighlight>
 
{{out}}
Line 2,074 ⟶ 2,179:
=={{header|Kotlin}}==
{{trans|Java}}
<langsyntaxhighlight lang="scala">// version 1.2.0
 
import java.util.concurrent.ThreadLocalRandom
Line 2,157 ⟶ 2,262:
thread(name = "transferrer") { buckets.transferRandomAmount() }
thread(name = "printer") { buckets.print() }
}</langsyntaxhighlight>
 
Sample output:
Line 2,177 ⟶ 2,282:
=={{header|Lasso}}==
Lasso thread objects are thread-safe by design.
<langsyntaxhighlight lang="lasso">define atomic => thread {
data
private buckets = staticarray_join(10, void),
Line 2,252 ⟶ 2,357:
stdoutnl(#buckets->asString + " -- total: " + #total)
}
stdoutnl(`ERROR: totals no longer match: ` + #initial_total + ', ' + #total)</langsyntaxhighlight>
 
{{out}}
Line 2,265 ⟶ 2,370:
=={{header|Logtalk}}==
The following example can be found in the Logtalk distribution and is used here with permission. Works when using SWI-Prolog, XSB, or YAP as the backend compiler.
<langsyntaxhighlight lang="logtalk">
:- object(buckets).
 
Line 2,373 ⟶ 2,478:
 
:- end_object.
</syntaxhighlight>
</lang>
 
Sample output:
 
<langsyntaxhighlight lang="logtalk">
?- buckets::start.
Sum of all bucket values: 52
Line 2,392 ⟶ 2,497:
[11,6,10,4,0,4,5,5,4,3]
true.
</syntaxhighlight>
</lang>
 
=={{header|Mathematica}} / {{header|Wolfram Language}}==
<langsyntaxhighlight Mathematicalang="mathematica">transfer[bucks_, src_, dest_, n_] :=
ReplacePart[
bucks, {src -> Max[bucks[[src]] - n, 0],
Line 2,415 ⟶ 2,520:
dest = RandomInteger[{1, 20}]},
bucks = transfer[bucks, src, dest,
RandomInteger[{1, bucks[[src]]}]]]; comp = True]]}];</langsyntaxhighlight>
{{out}}
<pre>Original sum: &lt;number&gt;
Line 2,428 ⟶ 2,533:
The program must be compiled with option <code>--threads:on</code>.
 
<langsyntaxhighlight Nimlang="nim">import locks
import math
import os
Line 2,555 ⟶ 2,660:
lock.deinitLock()
for c in terminate.mitems:
c.close()</langsyntaxhighlight>
 
{{out}}
Line 2,572 ⟶ 2,677:
Uses a lock for every bucket. Enforces a locking order to avoid deadlocks.
 
<langsyntaxhighlight lang="oz">declare
%%
%% INIT
Line 2,669 ⟶ 2,774:
thread for do {Smooth {Pick} {Pick}} end end
thread for do {Roughen {Pick} {Pick}} end end
for do {Display} {Time.delay 50} end</langsyntaxhighlight>
 
Sample output:
<langsyntaxhighlight lang="oz">buckets(50 50 50 50 50 50 50 50 50 50 ,,,) sum: 5000
buckets(24 68 58 43 78 85 43 66 14 48 ,,,) sum: 5000
buckets(36 33 59 38 39 23 55 51 43 45 ,,,) sum: 5000
Line 2,678 ⟶ 2,783:
buckets(51 51 49 50 51 51 51 49 49 49 ,,,) sum: 5000
buckets(43 28 27 60 77 41 36 48 72 70 ,,,) sum: 5000
...</langsyntaxhighlight>
 
=={{header|PARI/GP}}==
Line 2,684 ⟶ 2,789:
 
=={{header|Perl}}==
<langsyntaxhighlight lang="perl">use strict;
use 5.10.0;
 
Line 2,735 ⟶ 2,840:
};
 
$t1->join; $t2->join; $t3->join;</langsyntaxhighlight>
 
=={{header|Phix}}==
<!--<langsyntaxhighlight Phixlang="phix">(notonline)-->
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (no threads or critical sections in JavaScript)</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">nBuckets</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">20</span>
Line 2,788 ⟶ 2,893:
<span style="color: #000000;">wait_thread</span><span style="color: #0000FF;">(</span><span style="color: #000000;">threads</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">delete_cs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bucket_cs</span><span style="color: #0000FF;">)</span>
<!--</langsyntaxhighlight>-->
{{out}}
<pre>
Line 2,808 ⟶ 2,913:
child processes to handle the tasks, as this is the standard way
for general PicoLisp applications.
<langsyntaxhighlight PicoLisplang="picolisp">(seed (in "/dev/urandom" (rd 8)))
 
(de *Buckets . 15) # Number of buckets
Line 2,875 ⟶ 2,980:
(wait 2000) ) ) # Sleep two seconds
 
(wait)</langsyntaxhighlight>
Output:
<pre>70 236 582 30 395 215 525 653 502 825 129 769 722 440 708 -- Total: 6801
Line 2,887 ⟶ 2,992:
 
=={{header|PureBasic}}==
<langsyntaxhighlight PureBasiclang="purebasic">#Buckets=9
#TotalAmount=200
Global Dim Buckets(#Buckets)
Line 2,970 ⟶ 3,075:
Quit=#True ; Tell threads to shut down
WaitThread(Thread1): WaitThread(Thread2)
EndIf</langsyntaxhighlight>
 
=={{header|Python}}==
Line 2,977 ⟶ 3,082:
This code uses a ''threading.Lock'' to serialize access to the bucket set.
 
<langsyntaxhighlight lang="python">from __future__ import with_statement # required for Python 2.5
import threading
import random
Line 3,050 ⟶ 3,155:
# wait until all worker threads finish
t1.join()
t2.join()</langsyntaxhighlight>
 
Sample Output:
Line 3,064 ⟶ 3,169:
 
=={{header|Racket}}==
<langsyntaxhighlight lang="racket">#lang racket
 
(struct bucket (value [lock #:auto])
Line 3,164 ⟶ 3,269:
 
(thread (λ () (for ([_ (in-range 500000)]) (equalize (random 10) (random 10)))))
(thread (λ () (for ([_ (in-range 500000)]) (randomize (random 10) (random 10)))))</langsyntaxhighlight>
 
Sample output:
Line 3,189 ⟶ 3,294:
{{trans|Ruby}}
{{works with|Rakudo|2016.07}}
<syntaxhighlight lang="raku" perl6line>#| A collection of non-negative integers, with atomic operations.
class BucketStore {
Line 3,257 ⟶ 3,362:
exit 1;
}
}</langsyntaxhighlight>
 
{{out}}
Line 3,269 ⟶ 3,374:
 
=={{header|Ring}}==
<langsyntaxhighlight lang="ring">
# Project : Atomic updates
 
Line 3,312 ⟶ 3,417:
bucket[a1] = bucket[a1] - transfer
bucket[a2] = bucket[a2] + transfer
</syntaxhighlight>
</lang>
Output:
<pre>
Line 3,321 ⟶ 3,426:
 
=={{header|Ruby}}==
<langsyntaxhighlight Rubylang="ruby">require 'thread'
 
# A collection of buckets, filled with random non-negative integers.
Line 3,414 ⟶ 3,519:
exit 1
end
end</langsyntaxhighlight>
 
Sample Output:
Line 3,423 ⟶ 3,528:
 
=={{header|Run BASIC}}==
<langsyntaxhighlight lang="runbasic">DIM bucket(10)
FOR i = 1 TO 10 : bucket(i) = int(RND(0)*100) : NEXT
 
Line 3,456 ⟶ 3,561:
bucket(a1) = bucket(a1) - transfer
bucket(a2) = bucket(a2) + transfer
END FUNCTION</langsyntaxhighlight>
<pre> Display: 24 50 50 85 63 49 50 91 10 2 Total:474
Flatten: 47 47 47 47 47 47 47 47 47 51 Total:474
Line 3,463 ⟶ 3,568:
=={{header|Rust}}==
{{libheader|rand}}
<langsyntaxhighlight lang="rust">extern crate rand;
 
use std::sync::{Arc, Mutex};
Line 3,535 ⟶ 3,640:
thread::sleep(sleep_time);
}
}</langsyntaxhighlight>
 
=={{header|Scala}}==
<syntaxhighlight lang="scala">
<lang Scala>
object AtomicUpdates {
 
Line 3,614 ⟶ 3,719:
}
}
</syntaxhighlight>
</lang>
=={{header|Smalltalk}}==
{{works with|Smalltalk/X}}
<langsyntaxhighlight Smalltalklang="smalltalk">NUM_BUCKETS := 10.
"create and preset with random data"
buckets := (1 to:NUM_BUCKETS)
Line 3,684 ⟶ 3,789:
monitor terminate.
 
Stdout printCR: e'performed {count_equalizations} equalizations and {count_randomizations} randomizations'.</langsyntaxhighlight>
{{out}}
<pre>#(3940 3940 3940 3940 3939 3940 3940 3940 3940 3939) sum=39398
Line 3,701 ⟶ 3,806:
=={{header|Swift}}==
 
<langsyntaxhighlight lang="swift">import Foundation
 
final class AtomicBuckets: CustomStringConvertible {
Line 3,787 ⟶ 3,892:
chaos.activate()
 
dispatchMain()</langsyntaxhighlight>
 
{{out}}
Line 3,803 ⟶ 3,908:
<br>
{{works with|Tcl|8.5}}
<langsyntaxhighlight lang="tcl">package require Thread
package require Tk
 
Line 3,904 ⟶ 4,009:
tkwait window .
tsv::set still going 0
thread::broadcast thread::exit</langsyntaxhighlight>
 
=={{header|Wren}}==
Line 3,913 ⟶ 4,018:
 
Fibers are cooperatively (rather than preemptively) scheduled and only one fiber can run at a time. Consequently, simultaneous operations are impossible and all operations are therefore atomic by their nature.
<langsyntaxhighlight ecmascriptlang="wren">import "random" for Random
import "scheduler" for Scheduler
import "timer" for Timer
import "./math" for Nums
 
var Rnd = Random.new()
Line 3,993 ⟶ 4,098:
break
}
}</langsyntaxhighlight>
 
{{out}}
Line 4,013 ⟶ 4,118:
=={{header|zkl}}==
Threads and thread safe objects (locks, lists, ints, etc) are built in.
<langsyntaxhighlight lang="zkl">class B{
const N=10;
var [const]
Line 4,041 ⟶ 4,146:
 
fcn threadA(b){ while(1) { b.transferArb(); } }
fcn threadE(b){ while(1) { b.transferEq(); } }</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">b:=B();
do(10){ threadA.launch(b); } do(10){ threadE.launch(b); }
 
Line 4,050 ⟶ 4,155:
vm.numThreads," threads");
Atomic.sleep(2.5);
}</langsyntaxhighlight>
{{out}}
<pre>
Line 4,067 ⟶ 4,172:
</pre>
Another solution, using a Pipe as a "holding tank". Pipes are thread safe queues. This code just moves the values to and from the pipe to synchronize changes. The use of this class is the same as above, just change b:=B() to b:=C();
<langsyntaxhighlight lang="zkl">class C{
const N=10;
var [const]
Line 4,096 ⟶ 4,201:
v2;
}
}</langsyntaxhighlight>
 
 
Line 4,106 ⟶ 4,211:
{{omit from|LaTeX}}
{{omit from|M4}}
{{omit from|ML/I}}
{{omit from|Make}}
{{omit from|ML/I}}
{{omit from|PlainTeX}}
{{omit from|TI-89 BASIC}} <!-- Does not have concurrency or background processes. -->
9,482

edits