Task: Atomic updates
C#: using System; 
using System.Threading; 
public class ThreadSafeBuckets
{
    
    
    Random rand = new Random();
    int[] Buckets;
    object[] locks; 
    public int BucketCount { get; private set; }
    public ThreadSafeBuckets(int bucketcount)
    {
        
        BucketCount = bucketcount;
        Buckets = new int[bucketcount];
        locks = new object[bucketcount];
        int startingtotal = 0;
        for (int i = 0; i < BucketCount; i++)
        {
            locks[i] = new object();
            Buckets[i] = rand.Next(30);
            startingtotal += Buckets[i];
        }
        
        Console.WriteLine("Starting total: " + startingtotal);
    }
    public int GetBucketValue(int i)
    {
        return Buckets[i];
    }
    public void Transfer(int i, int j, int amount)
    {
        
        if (i > BucketCount || j > BucketCount || i < 0 || j < 0 ||
            i == j || amount < 0)
            return;

        
        lock (locks[Math.Min(i, j)])
            lock (locks[Math.Max(i, j)])
            {
                
                amount = Math.Min(amount, Buckets[i]);

                
                Buckets[i] -= amount;
                Buckets[j] += amount;
            }
    }

    public void PrintBuckets()
    {
        int counter = 0;
        
        for (int i = 0; i < BucketCount; i++)
        {
            Monitor.Enter(locks[i]);
            Console.Write(Buckets[i] + " ");
            counter += Buckets[i];
        }
        
        Console.Write("= " + counter);
        Console.WriteLine();

        foreach (var l in locks)
            Monitor.Exit(l);
    }
}

class Program
{
    static ThreadSafeBuckets TSBs;

    public static void Main(){
        
        TSBs = new ThreadSafeBuckets(10);
        TSBs.PrintBuckets();
        
        new Thread(new ThreadStart(EqualizerThread)).Start();
        Thread.Sleep(1);
        
        new Thread(new ThreadStart(RandomizerThread)).Start();
        
        PrinterThread();
    }
    
    static void EqualizerThread()
    {
        Random rand = new Random();
        while (true)
        {
            
            int b1 = rand.Next(TSBs.BucketCount);
            int b2 = rand.Next(TSBs.BucketCount);
            
            int diff = TSBs.GetBucketValue(b1) - TSBs.GetBucketValue(b2);
            
            if (diff < 0)
                TSBs.Transfer(b2, b1, -diff / 2);
            else
                TSBs.Transfer(b1, b2, diff/2);
        }
    }
    
    static void RandomizerThread()
    {
        Random rand = new Random();
        while (true)
        {
            int b1 = rand.Next(TSBs.BucketCount);
            int b2 = rand.Next(TSBs.BucketCount);
            int diff = rand.Next(TSBs.GetBucketValue(b1));
            TSBs.Transfer(b1, b2, diff);
        }
    }
    
    static void PrinterThread()
    {
        while (true)
        {
            Thread.Sleep(50); 
            TSBs.PrintBuckets();
        }
    }
}

C++: #include <algorithm>
#include <array>
#include <chrono>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <random>
#include <thread>

using namespace std;

constexpr int bucket_count = 15;

void equalizer(array<int, bucket_count>& buckets,
               array<mutex, bucket_count>& bucket_mutex) {
    random_device rd;
    mt19937 gen(rd());
    uniform_int_distribution<> dist_bucket(0, bucket_count - 1);

    while (true) {
        int from = dist_bucket(gen);
        int to = dist_bucket(gen);
        if (from != to) {
            lock_guard<mutex> lock_first(bucket_mutex[min(from, to)]);
            lock_guard<mutex> lock_second(bucket_mutex[max(from, to)]);
            int diff = buckets[from] - buckets[to];
            int amount = abs(diff / 2);
            if (diff < 0) {
                swap(from, to);
            }
            buckets[from] -= amount;
            buckets[to] += amount;
        }
    }
}

void randomizer(array<int, bucket_count>& buckets,
                array<mutex, bucket_count>& bucket_mutex) {
    random_device rd;
    mt19937 gen(rd());
    uniform_int_distribution<> dist_bucket(0, bucket_count - 1);

    while (true) {
        int from = dist_bucket(gen);
        int to = dist_bucket(gen);
        if (from != to) {
            lock_guard<mutex> lock_first(bucket_mutex[min(from, to)]);
            lock_guard<mutex> lock_second(bucket_mutex[max(from, to)]);
            uniform_int_distribution<> dist_amount(0, buckets[from]);
            int amount = dist_amount(gen);
            buckets[from] -= amount;
            buckets[to] += amount;
        }
    }
}

void print_buckets(const array<int, bucket_count>& buckets) {
    int total = 0;
    for (const int& bucket : buckets) {
        total += bucket;
        cout << setw(3) << bucket << ' ';
    }
    cout << "= " << setw(3) << total << endl;
}

int main() {
    random_device rd;
    mt19937 gen(rd());
    uniform_int_distribution<> dist(0, 99);

    array<int, bucket_count> buckets;
    array<mutex, bucket_count> bucket_mutex;
    for (int& bucket : buckets) {
        bucket = dist(gen);
    }
    print_buckets(buckets);

    thread t_eq(equalizer, ref(buckets), ref(bucket_mutex));
    thread t_rd(randomizer, ref(buckets), ref(bucket_mutex));

    while (true) {
        this_thread::sleep_for(chrono::seconds(1));
        for (mutex& mutex : bucket_mutex) {
            mutex.lock();
        }
        print_buckets(buckets);
        for (mutex& mutex : bucket_mutex) {
            mutex.unlock();
        }
    }
    return 0;
}