Atomic updates: Difference between revisions
m
→{{header|Wren}}: Minor tidy
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}}==
<
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 ;</
{{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}}==
<
with Ada.Numerics.Discrete_Random;
Line 214:
end;
end loop;
end Test_Updates;</
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}}==
<
loop, %Buckets% {
Random, rnd, 0,50
Line 271:
Res.= ">"
return Res
}</
=={{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.
<
DIM Buckets%(100)
Line 327:
PROC_killtimer(tid1%)
PROC_killtimer(tid2%)
ENDPROC</
=={{header|C}}==
Line 335:
{{libheader|pthread}}
<
#include <stdlib.h>
#include <stdbool.h>
Line 445:
for(i=0; i < N_BUCKETS; i++) pthread_mutex_destroy(bucket_mutex+i);
return EXIT_SUCCESS;
}</
===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.
<
#include <stdlib.h>
#include <omp.h>
Line 499:
return 0;
}</
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</
=={{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
<
using System; //Rand class
using System.Threading; //Thread, Mutex classes
Line 640:
}
}
}</
Sample Output:
Line 657:
{{works with|C++11}}
<
#include <array>
#include <chrono>
Line 748:
}
return 0;
}</
=={{header|Clojure}}==
Function returning a new map containing altered values:
<
(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))))</
Since clojure data structures are immutable, atomic mutability occurs via a reference, in this case an atom:
<
(swap! *data* xfer :a :b 50) ;; atomically results in *data* holding {:a 50 :b 150}</
Now for the test:
<
(let [{a-val a b-val b} m
diff (- a-val b-val)
Line 784:
(.start thread-eq)
(.start thread-rand)</
=={{header|Common Lisp}}==
Depends on libraries in Quicklisp. STMX is a library that provides Software Transactional Memory.
<
(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))))))</
{{out}}
<
#<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</
=={{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.
<
import std.conv: text;
import std.random: uniform, Xorshift;
Line 955:
task!equalize(data).executeInNewThread();
task!display(data).executeInNewThread();
}</
{{out}}
<pre>N. transfers, buckets, buckets sum:
Line 981:
This example uses a Java AWT window to display the current state of the buckets.
<
pragma.syntax("0.9")
Line 1,103:
frame.show()
interp.waitAtTop(done)</
=={{header|Erlang}}==
Line 1,120:
[0,11,7,0,4,16,7,0,10,0] = 55
</pre>
<syntaxhighlight 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>
=={{header|Euphoria}}==
<
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</
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):
<
open System.Threading
Line 1,387:
Thread.Sleep 100
bucket.Print()
</syntaxhighlight>
This program performs a million concurrent transfers. Typical output is:
<
[|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>
=={{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}}==
<
import (
Line 1,602 ⟶ 1,707:
}
}
}</
{{out}}
<pre>
Line 1,616 ⟶ 1,721:
=={{header|Groovy}}==
Solution:
<
def cells = []
Line 1,694 ⟶ 1,799:
}
Thread.sleep(500)
}</
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.
<
import Control.Concurrent (forkIO, threadDelay)
Line 1,794 ⟶ 1,899:
forkIO (roughen buckets)
forkIO (smooth buckets)
display buckets</
Sample output:
Line 1,816 ⟶ 1,921:
The following only works in Unicon:
<
procedure main(A)
Line 1,848 ⟶ 1,953:
buckets[b1] -:= x
buckets[b2] +:= x
end</
Sample run:
Line 1,869 ⟶ 1,974:
=={{header|Java}}==
{{works with|Java|8+}}
<
import java.util.concurrent.ThreadLocalRandom;
Line 1,974 ⟶ 2,079:
}
}
}</
{{out}}
Line 1,992 ⟶ 2,097:
=={{header|Julia}}==
<
function runall()
Line 2,051 ⟶ 2,156:
end
runall()</
{{out}}
Line 2,074 ⟶ 2,179:
=={{header|Kotlin}}==
{{trans|Java}}
<
import java.util.concurrent.ThreadLocalRandom
Line 2,157 ⟶ 2,262:
thread(name = "transferrer") { buckets.transferRandomAmount() }
thread(name = "printer") { buckets.print() }
}</
Sample output:
Line 2,177 ⟶ 2,282:
=={{header|Lasso}}==
Lasso thread objects are thread-safe by design.
<
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)</
{{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.
<
:- object(buckets).
Line 2,373 ⟶ 2,478:
:- end_object.
</syntaxhighlight>
Sample output:
<
?- 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>
=={{header|Mathematica}} / {{header|Wolfram Language}}==
<
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]]}];</
{{out}}
<pre>Original sum: <number>
Line 2,428 ⟶ 2,533:
The program must be compiled with option <code>--threads:on</code>.
<
import math
import os
Line 2,555 ⟶ 2,660:
lock.deinitLock()
for c in terminate.mitems:
c.close()</
{{out}}
Line 2,572 ⟶ 2,677:
Uses a lock for every bucket. Enforces a locking order to avoid deadlocks.
<
%%
%% 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</
Sample output:
<
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
...</
=={{header|PARI/GP}}==
Line 2,684 ⟶ 2,789:
=={{header|Perl}}==
<
use 5.10.0;
Line 2,735 ⟶ 2,840:
};
$t1->join; $t2->join; $t3->join;</
=={{header|Phix}}==
<!--<
<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>
<!--</
{{out}}
<pre>
Line 2,808 ⟶ 2,913:
child processes to handle the tasks, as this is the standard way
for general PicoLisp applications.
<
(de *Buckets . 15) # Number of buckets
Line 2,875 ⟶ 2,980:
(wait 2000) ) ) # Sleep two seconds
(wait)</
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}}==
<
#TotalAmount=200
Global Dim Buckets(#Buckets)
Line 2,970 ⟶ 3,075:
Quit=#True ; Tell threads to shut down
WaitThread(Thread1): WaitThread(Thread2)
EndIf</
=={{header|Python}}==
Line 2,977 ⟶ 3,082:
This code uses a ''threading.Lock'' to serialize access to the bucket set.
<
import threading
import random
Line 3,050 ⟶ 3,155:
# wait until all worker threads finish
t1.join()
t2.join()</
Sample Output:
Line 3,064 ⟶ 3,169:
=={{header|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)))))</
Sample output:
Line 3,189 ⟶ 3,294:
{{trans|Ruby}}
{{works with|Rakudo|2016.07}}
<syntaxhighlight lang="raku"
class BucketStore {
Line 3,257 ⟶ 3,362:
exit 1;
}
}</
{{out}}
Line 3,269 ⟶ 3,374:
=={{header|Ring}}==
<
# Project : Atomic updates
Line 3,312 ⟶ 3,417:
bucket[a1] = bucket[a1] - transfer
bucket[a2] = bucket[a2] + transfer
</syntaxhighlight>
Output:
<pre>
Line 3,321 ⟶ 3,426:
=={{header|Ruby}}==
<
# A collection of buckets, filled with random non-negative integers.
Line 3,414 ⟶ 3,519:
exit 1
end
end</
Sample Output:
Line 3,423 ⟶ 3,528:
=={{header|Run BASIC}}==
<
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</
<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}}
<
use std::sync::{Arc, Mutex};
Line 3,535 ⟶ 3,640:
thread::sleep(sleep_time);
}
}</
=={{header|Scala}}==
<syntaxhighlight lang="scala">
object AtomicUpdates {
Line 3,614 ⟶ 3,719:
}
}
</syntaxhighlight>
=={{header|Smalltalk}}==
{{works with|Smalltalk/X}}
<
"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'.</
{{out}}
<pre>#(3940 3940 3940 3940 3939 3940 3940 3940 3940 3939) sum=39398
Line 3,701 ⟶ 3,806:
=={{header|Swift}}==
<
final class AtomicBuckets: CustomStringConvertible {
Line 3,787 ⟶ 3,892:
chaos.activate()
dispatchMain()</
{{out}}
Line 3,803 ⟶ 3,908:
<br>
{{works with|Tcl|8.5}}
<
package require Tk
Line 3,904 ⟶ 4,009:
tkwait window .
tsv::set still going 0
thread::broadcast thread::exit</
=={{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.
<
import "scheduler" for Scheduler
import "timer" for Timer
import "./math" for Nums
var Rnd = Random.new()
Line 3,993 ⟶ 4,098:
break
}
}</
{{out}}
Line 4,013 ⟶ 4,118:
=={{header|zkl}}==
Threads and thread safe objects (locks, lists, ints, etc) are built in.
<
const N=10;
var [const]
Line 4,041 ⟶ 4,146:
fcn threadA(b){ while(1) { b.transferArb(); } }
fcn threadE(b){ while(1) { b.transferEq(); } }</
<
do(10){ threadA.launch(b); } do(10){ threadE.launch(b); }
Line 4,050 ⟶ 4,155:
vm.numThreads," threads");
Atomic.sleep(2.5);
}</
{{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();
<
const N=10;
var [const]
Line 4,096 ⟶ 4,201:
v2;
}
}</
Line 4,106 ⟶ 4,211:
{{omit from|LaTeX}}
{{omit from|M4}}
{{omit from|Make}}
{{omit from|ML/I}}
{{omit from|PlainTeX}}
{{omit from|TI-89 BASIC}} <!-- Does not have concurrency or background processes. -->
|