Jump to content

Atomic updates: Difference between revisions

(Rename Perl 6 -> Raku, alphabetize, minor clean-up)
Line 2,420:
Current sum: &lt;same number, stays fixed&gt;</pre>
This simply uses a variable named <tt>comp</tt> to determine whether or not it is currently computing something.
 
=={{header|Nim}}==
We use Threads objects which are mapped to system threads. Access to buckets is protected by locks (one lock per bucket). We use also a lock to protect the random number generator which is not thread-safe.
 
The main thread sleeps during 10 seconds, then ask the threads to terminate. For this purpose, we could have used a simple boolean but we have rather chosen to send the termination message via a channel. So each thread receives the number of the channel to listen to and checks regularly if a message ask it to terminate.
 
<lang Nim>import locks
import math
import os
import random
 
const N = 10 # Number of buckets.
const MaxInit = 99 # Maximum initial value for buckets.
 
var buckets: array[1..N, Natural] # Array of buckets.
var bucketLocks: array[1..N, Lock] # Array of bucket locks.
var randomLock: Lock # Lock to protect the random number generator.
var terminate: array[3, Channel[bool]] # Used to ask threads to terminate.
 
#---------------------------------------------------------------------------------------------------
 
proc getTwoIndexes(): tuple[a, b: int] =
## Get two indexes from the random number generator.
 
result.a = rand(1..N)
result.b = rand(2..N)
if result.b == result.a: result.b = 1
 
#---------------------------------------------------------------------------------------------------
 
proc equalize(num: int) {.thread.} =
## Try to equalize two buckets.
 
var b1, b2: int # Bucket indexes.
 
while true:
 
# Select the two buckets to "equalize".
withLock randomLock:
(b1, b2) = getTwoIndexes()
if b1 > b2: swap b1, b2 # We want "b1 < b2" to avoid deadlocks.
 
# Perform equalization.
withLock bucketLocks[b1]:
withLock bucketLocks[b2]:
let target = (buckets[b1] + buckets[b2]) div 2
let delta = target - buckets[b1]
inc buckets[b1], delta
dec buckets[b2], delta
 
# Check termination.
let (available, stop) = tryRecv terminate[num]
if available and stop: break
 
#---------------------------------------------------------------------------------------------------
 
proc distribute(num: int) {.thread.} =
## Redistribute contents of two buckets.
 
var b1, b2: int # Bucket indexes.
var factor: float # Ratio used to compute the new value for "b1".
 
while true:
 
# Select the two buckets for redistribution and the redistribution factor.
withLock randomLock:
(b1, b2) = getTwoIndexes()
factor = rand(0.0..1.0)
if b1 > b2: swap b1, b2 # We want "b1 < b2" to avoid deadlocks..
 
# Perform redistribution.
withLock bucketLocks[b1]:
withLock bucketLocks[b2]:
let sum = buckets[b1] + buckets[b2]
let value = (sum.toFloat * factor).toInt
buckets[b1] = value
buckets[b2] = sum - value
 
# Check termination.
let (available, stop) = tryRecv terminate[num]
if available and stop: break
 
#---------------------------------------------------------------------------------------------------
 
proc display(num: int) {.thread.} =
## Display the content of buckets and the sum (which should be constant).
 
while true:
for i in 1..N: acquire bucketLocks[i]
echo buckets, " Total = ", sum(buckets)
for i in countdown(N, 1): release bucketLocks[i]
os.sleep(1000)
 
# Check termination.
let (available, stop) = tryRecv terminate[num]
if available and stop: break
 
#———————————————————————————————————————————————————————————————————————————————————————————————————
 
randomize()
 
# Initialize the buckets with a random value.
for bucket in buckets.mitems:
bucket = rand(1..MaxInit)
 
# Initialize the locks.
randomLock.initLock()
for lock in bucketLocks.mitems:
lock.initLock()
 
# Open the channels.
for c in terminate.mitems:
c.open()
 
# Create and launch the threads.
var tequal, tdist, tdisp: Thread[int]
tequal.createThread(equalize, 0)
tdist.createThread(distribute, 1)
tdisp.createThread(display, 2)
 
sleep(10000)
 
# Ask the threads to stop.
for c in terminate.mitems:
c.send(true)
 
joinThreads([tequal, tdist, tdisp])
 
# Free resources.
randomLock.deinitLock()
for lock in bucketLocks.mitems:
lock.deinitLock()
for c in terminate.mitems:
c.close()</lang>
 
{{out}}
<pre>Total = 588 [92, 63, 33, 68, 66, 37, 26, 66, 77, 60]
Total = 588 [91, 3, 41, 126, 34, 3, 25, 92, 13, 160]
Total = 588 [129, 9, 80, 6, 68, 8, 73, 45, 69, 101]
Total = 588 [87, 71, 144, 20, 11, 54, 72, 48, 63, 18]
Total = 588 [158, 71, 110, 51, 19, 60, 27, 31, 10, 51]
Total = 588 [97, 43, 5, 70, 71, 104, 25, 17, 112, 44]
Total = 588 [68, 50, 12, 51, 128, 8, 21, 143, 53, 54]
Total = 588 [31, 47, 156, 81, 69, 5, 28, 76, 66, 29]
Total = 588 [97, 3, 27, 82, 42, 120, 72, 74, 39, 32]
Total = 588 [30, 39, 79, 109, 62, 62, 13, 14, 54, 126]</pre>
 
=={{header|Oz}}==
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.