Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
128
Task/Atomic-updates/Nim/atomic-updates.nim
Normal file
128
Task/Atomic-updates/Nim/atomic-updates.nim
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
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()
|
||||
Loading…
Add table
Add a link
Reference in a new issue