Channel Select - fthoms/jiminy GitHub Wiki

Channel Select

Often you will need to receive messages from multiple channels at once. Since Receive() is a blocking operation, Jiminy provides a means to Select between channels. Based on which channel has a message waiting, the associated message handler is invoked.

In the case of non-blocking selects, there is also a default handler.

Blocking Select

This starts by creating a channel selector, which we provide with cases to select from:

var err = Channel.Select()
	.Case(chan1, m => Console.WriteLine("channel 1"))
	.Case(chan2, m => Console.WriteLine("channel 2"))
	.Receive();

Calling Receive() will block until

  • there is a message on one of the channels, in which case the associated handler is invoked and null is returned, or
  • the channel is closed with no unconsumed messages, in which case an error is returned, or
  • either of the handlers throws an exception, in which case the exception message is returned in the Error

The following code illustrates this more thoroughly:

    sealed class Select : IExample {
        public void Run() {
            var done = Channel.Make<bool>();
            Task.Run(() => Receive(MakeChan("first"), MakeChan("second"), MakeChan("third"), done));
            done.Receive();
            Console.WriteLine("done");
        }

        IChannel<string> MakeChan(string name) {
            var chan = Channel.Make<string>();
            Task.Run(() =>
            {
                for(var i = 0; i < 5; i++) {
                    chan.Send($"{name} {i}");
                }
                chan.Close();
            });
            return chan;
        }

        void Receive(IChannel<string> ch1, IChannel<string> ch2, IChannel<string> ch3, IChannel<bool> done) {
            var error = Error.Nil;
            while (error == null) {
                error = Channel.Select()
                    .Case(ch1, m => Console.WriteLine(m))
                    .Case(ch2, m => Console.WriteLine(m))
                    .Case(ch3, m => Console.WriteLine(m))
                    .Receive();
            }
            done.Send(true);
        }
    }

Non-blocking Select

Non-blocking select is an operation that will execute the default action if there are no messages available on any of the channels, either because one, some or all channels are closed, or because there are no waiting messages at the time of execution.

The following code will print "no messages" to the console:

sealed class ChannelDefaultSelect : IExample {
    public void Run() {
        var chan1 = Channel.Make<int>();
        var chan2 = Channel.Make<int>();
        var err = Channel.Select()
            .Case(chan1, _ => Console.WriteLine("channel 1"))
            .Case(chan2, _ => Console.WriteLine("channel 1"))
            .Otherwise(() => Console.WriteLine("no messages"));
    }
}

Again, err is null if any of the handlers succeed. One key difference with blocking select is that err is null even if all channels are closed (in which case the default handler is invoked).

⚠️ **GitHub.com Fallback** ⚠️