Task: Checkpoint synchronization



C#: using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Rosetta.CheckPointSync;

public class Program
{
    public async Task Main()
    {
        RobotBuilder robotBuilder = new RobotBuilder();
        Task work = robotBuilder.BuildRobots(
            "Optimus Prime", "R. Giskard Reventlov", "Data", "Marvin",
            "Bender", "Number Six", "C3-PO", "Dolores");
        await work;
    }

    public class RobotBuilder
    {
        static readonly string[] parts = { "Head", "Torso", "Left arm", "Right arm", "Left leg", "Right leg" };
        static readonly Random rng = new Random();
        static readonly object key = new object();

        public Task BuildRobots(params string[] robots)
        {
            int r = 0;
            Barrier checkpoint = new Barrier(parts.Length, b => {
                Console.WriteLine($"{robots[r]} assembled. Hello, {robots[r]}!");
                Console.WriteLine();
                r++;
            });
            var tasks = parts.Select(part => BuildPart(checkpoint, part, robots)).ToArray();
            return Task.WhenAll(tasks);
        }

        private static int GetTime()
        {
            
            
            lock (key) {
                return rng.Next(100, 1000);
            }
        }

        private async Task BuildPart(Barrier barrier, string part, string[] robots)
        {
            foreach (var robot in robots) {
                int time = GetTime();
                Console.WriteLine($"Constructing {part} for {robot}. This will take {time}ms.");
                await Task.Delay(time);
                Console.WriteLine($"{part} for {robot} finished.");
                barrier.SignalAndWait();
            }
        }

    }
    
}



Java: import java.util.Scanner;
import java.util.Random;

public class CheckpointSync{
	public static void main(String[] args){
		System.out.print("Enter number of workers to use: ");
		Scanner in = new Scanner(System.in);
		Worker.nWorkers = in.nextInt();
		System.out.print("Enter number of tasks to complete:");
		runTasks(in.nextInt());
	}
	
	
	private static void runTasks(int nTasks){
		for(int i = 0; i < nTasks; i++){
			System.out.println("Starting task number " + (i+1) + ".");
			runThreads();
			Worker.checkpoint();
		}
	}
	
	
	private static void runThreads(){
		for(int i = 0; i < Worker.nWorkers; i ++){
			new Thread(new Worker(i+1)).start();
		}
	}
	
	
	public static class Worker implements Runnable{
		public Worker(int threadID){
			this.threadID = threadID;
		}
		public void run(){
			work();
		}
		
		
		private synchronized void work(){
			try {
				int workTime = rgen.nextInt(900) + 100;
				System.out.println("Worker " + threadID + " will work for " + workTime + " msec.");
				Thread.sleep(workTime); 
				nFinished++; 
				System.out.println("Worker " + threadID + " is ready");
			} catch (InterruptedException e) {
				System.err.println("Error: thread execution interrupted");
				e.printStackTrace();
			}
		}
		
		
		public static synchronized void checkpoint(){
			while(nFinished != nWorkers){
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					System.err.println("Error: thread execution interrupted");
					e.printStackTrace();
				}
			}
			nFinished = 0;
		}
	
		
		private int threadID;
		
		
		private static Random rgen = new Random();
		private static int nFinished = 0;
		public static int nWorkers = 0;
	}
}