Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
94
Task/Atomic-updates/Ruby/atomic-updates.rb
Normal file
94
Task/Atomic-updates/Ruby/atomic-updates.rb
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
require 'thread'
|
||||
|
||||
# A collection of buckets, filled with random non-negative integers.
|
||||
# There are atomic operations to look at the bucket contents, and
|
||||
# to move amounts between buckets.
|
||||
class BucketStore
|
||||
|
||||
# Creates a BucketStore with +nbuckets+ buckets. Fills each bucket
|
||||
# with a random non-negative integer.
|
||||
def initialize nbuckets
|
||||
# Create an array for the buckets
|
||||
@buckets = (0...nbuckets).map { rand(1024) }
|
||||
|
||||
# Mutex used to make operations atomic
|
||||
@mutex = Mutex.new
|
||||
end
|
||||
|
||||
# Returns an array with the contents of all buckets.
|
||||
def buckets
|
||||
@mutex.synchronize { Array.new(@buckets) }
|
||||
end
|
||||
|
||||
# Transfers _amount_ to bucket at array index _destination_,
|
||||
# from bucket at array index _source_.
|
||||
def transfer destination, source, amount
|
||||
# Do nothing if both buckets are same
|
||||
return nil if destination == source
|
||||
|
||||
@mutex.synchronize do
|
||||
# Clamp amount to prevent negative value in bucket
|
||||
amount = [amount, @buckets[source]].min
|
||||
|
||||
@buckets[source] -= amount
|
||||
@buckets[destination] += amount
|
||||
end
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# Create bucket store
|
||||
bucket_store = BucketStore.new 8
|
||||
|
||||
# Get total amount in the store
|
||||
TOTAL = bucket_store.buckets.inject { |a, b| a += b }
|
||||
|
||||
# Start a thread to equalize buckets
|
||||
Thread.new do
|
||||
loop do
|
||||
# Pick 2 buckets
|
||||
buckets = bucket_store.buckets
|
||||
first = rand buckets.length
|
||||
second = rand buckets.length
|
||||
|
||||
# Swap buckets so that _first_ has not more than _second_
|
||||
first, second = second, first if buckets[first] > buckets[second]
|
||||
|
||||
# Transfer half of the difference, rounded down
|
||||
bucket_store.transfer first, second, (buckets[second] - buckets[first]) / 2
|
||||
end
|
||||
end
|
||||
|
||||
# Start a thread to distribute values among buckets
|
||||
Thread.new do
|
||||
loop do
|
||||
# Pick 2 buckets
|
||||
buckets = bucket_store.buckets
|
||||
first = rand buckets.length
|
||||
second = rand buckets.length
|
||||
|
||||
# Transfer random amount to _first_ from _second_
|
||||
bucket_store.transfer first, second, rand(buckets[second])
|
||||
end
|
||||
end
|
||||
|
||||
# Loop to display buckets
|
||||
loop do
|
||||
sleep 1
|
||||
|
||||
buckets = bucket_store.buckets
|
||||
|
||||
# Compute the total value in all buckets.
|
||||
# We calculate this outside BucketStore so BucketStore can't cheat by
|
||||
# always reporting the same value.
|
||||
n = buckets.inject { |a, b| a += b }
|
||||
|
||||
# Display buckets and total
|
||||
printf "%s, total %d\n", (buckets.map { |v| sprintf "%4d", v }.join " "), n
|
||||
|
||||
if n != TOTAL
|
||||
# This should never happen
|
||||
$stderr.puts "ERROR: Total changed from #{TOTAL} to #{n}"
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue