Interactive Chord Example - vilinski/nemerle GitHub Wiki

What we have here is a basic client-server model where commands are entered in one thread and processed in another. It provides an interactive example of how to use chords. It might be a good idea to compile and play with it before analyzing it.

It has four main parts:

  • initialization code
  • a chord
  • a method run in a client thread where commands are entered
  • a method run in a server thread where commands are processed
using System.Console;
using System.Threading;
using Nemerle.Concurrency;

module EntryPoint{
    public Main() : void{
        _ = ClientServerCalculator(); //Go to the class's constructor to follow along.
    }
}


class ClientServerCalculator
{
    serverThread : Thread;
    clientThread : Thread;
    mutable running : bool = true;
    mutable suspended : bool = false;

    public this() {
        serverThread = Thread(ThreadStart(this.RunServerLoop)); //Starts RunServerLoop in its own thread.
        clientThread = Thread(ThreadStart(this.EnterCmdLoop));  //Starts EnterCmdLoop in its own thread.
        
        serverThread.Start(); //Start the threads
        while(!serverThread.IsAlive){Thread.Sleep(10)}
        clientThread.Start();
        
    }

    [ChordMember]
    private Add (a : int, b : int) : void;
    [ChordMember]
    private Mul(c : int, d : int) : void;
    [ChordMember]
    private Suspend() : void;
    [ChordMember]
    private Exit() : void;

    //Get() is a chord. When called it will halt thread execution until one of its chord
    //members has been called, and then return.
    private Get () : string 
    chord {
        | Suspend => suspended = true; "Suspend Command"
        | Add => $"Add Command\n$a + $b = $(a + b)"
        | Mul => $"Mul Command\n$c * $d = $(c * d)"
        | Exit => "Exit Command"
    }

    private RunServerLoop() : void{
        match(running){
            | false => () //Exit
            | true => match(suspended){
                        | false =>{ //Process commands.
                                def got = Get(); //Will halt thread execution until a chord member has been called
                                WriteLine("Command Received:");
                                WriteLine(got);
                                RunServerLoop();
                            }
                        | true => Thread.Sleep(100); RunServerLoop() //Do nothing
                      }
        }
    }

    private EnterCmdLoop() : void {
        Thread.Sleep(200);//Gives the server a chance to write to the console before client does.
        Write("\nServer State: ");
        match(suspended){
        | true => Write("Suspended (Server will queue commands.)")
        | false => Write("Processing Commands")
        }
            
        Write("\nAvailable commands for server are add, mul, suspend, resume, exit\nYour Command:");
        match(ReadLine()){
            | "add" => Add(InputNumber(),InputNumber()); EnterCmdLoop()
            | "mul" => Mul(InputNumber(),InputNumber()); EnterCmdLoop()
            | "suspend" when(suspended == false) => Suspend(); EnterCmdLoop()
            | "suspend" => WriteLine("Server Already Suspended"); EnterCmdLoop()
            | "resume" when(suspended == true) => suspended = false; WriteLine("Server Resuming"); EnterCmdLoop()
            | "resume" => WriteLine("Server Already Running"); EnterCmdLoop()
            | "exit" => {running = false; Exit()}
            | _ => WriteLine("\nCommand not found.\n"); EnterCmdLoop()
        }
    }

    private InputNumber() : int{ //Returns a number from console input.
        Write("Input an integer:");
        try{
            int.Parse(ReadLine());
        }
        catch{
            | _ => {WriteLine("\nError! Not a number."); InputNumber();}
        }
    }
}
⚠️ **GitHub.com Fallback** ⚠️