Skip to content

Framework to enable CSP (Communicating sequential processes) for process synchronization

License

Notifications You must be signed in to change notification settings

aliaslab-1984/Channels

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Channels

Framework to enable CSP (Communicating sequential processes) for process synchronization. It is based on the concept of channel and provides an internode queue based implementation built on RabbitMQ.

Description

A channel is composed by a read end and a write end, represented by the interfaces IChannelReader and IChannelWriter.

A channel is a synchronized queue of a given type T and is possible to use adapeters to create multitype channels.

Every read operation is unique, to multicast a single datum is necessary to use an ISubscribableChannel implementation.

On the channels is possible to perform synchronization oepration like: race (select) and barrier.

Here are some examples taken from the unittests:

    [TestCategory("Channels")]
    [TestMethod]
    public virtual void Sync()
    {
        int expected = 3;

        using (IChannel c = new Channel())
        {
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(Timeblok);
                c.Write(expected);
            });

            Assert.AreEqual(expected, c.Read());
        }
    }

    [TestCategory("Channels")]
    [TestMethod]
    public virtual void OutputAdapter()
    {
        int expected = 3;

        using (IChannel c = new Channel())
        using (IChannelReader ca = new FuncChannelOutputAdapter(c, p => p.ToString()))
        {
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(Timeblok);
                c.Write(expected);
            });

            Assert.AreEqual(expected.ToString(), ca.Read());
        }
    }

    [TestCategory("Channels")]
    [TestMethod]
    public virtual void InputAdapter()
    {
        int expected = 3;

        using (IChannel c = new Channel())
        using (IChannelWriter ca = new FuncChannelInputAdapter(c, p => p.ToString()))
        {
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(Timeblok);
                ca.Write(expected);
            });

            Assert.AreEqual(expected.ToString(), c.Read());
        }
    }

    [TestCategory("Channels")]
    [TestMethod]
    public virtual void CompositeChannel()
    {
        int expected = 3;
        using (IChannel c = new Channel())
        using (IChannel x = new CompositeChannel(
            new FuncChannelInputAdapter(c, p => Convert.ToInt32(p)),
            new FuncChannelOutputAdapter(c, p => p.ToString())))
        {
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(Timeblok);
                x.Write(expected.ToString());
            });

            Assert.AreEqual(expected.ToString(), x.Read());
        }
    }

    [TestCategory("Channels")]
    [TestMethod]
    public virtual void Pipe()
    {
        int expected = 3;

        using (IChannel c = new FuncChannelPipe(new Channel(), new Channel(), p => p))
        {
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(Timeblok);
                c.Write(expected);
            });

            Assert.AreEqual(expected, c.Read());
        }
    }

    [TestCategory("Channels")]
    [TestMethod]
    public virtual void SyncWrite()
    {
        int expected = 3;

        using (IChannel c = new Channel())
        using (IChannel w = new Channel())
        {
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(Timeblok);
                c.Read();
                c.Read();
                c.Write(expected);
                w.Write(0);
            });
            c.Write(0);
            c.Write(1);
            w.Read();
            Assert.AreEqual(expected, c.Read());
        }
    }

    [TestCategory("Channels")]
    [TestMethod]
    public virtual void Acc()
    {
        int a = 1, b = 2;
        int expected = a+b;

        using (IChannel c = new Channel())
        {
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(Timeblok);
                c.Write(a);
            });
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(Timeblok);
                c.Write(b);
            });

            Assert.AreEqual(expected, c.Read() + c.Read());
        }
    }

    [TestCategory("Channels")]
    [TestMethod]
    public virtual void Enumerate()
    {
        int count = 100;
        int[] expected = Enumerable.Range(0,count).ToArray();
        List actual = new List();

        using (IChannel c = new Channel(5))
        using (IChannel w = new Channel())
        {
            Task.Factory.StartNew(() =>
            {
                for (int i = 0; i < count; i++)
                    c.Write(i);

                c.Close();
            });
            Task.Factory.StartNew(() =>
            {
                foreach (int item in c.Enumerate())
                {
                    actual.Add(item);
                }

                w.Write(count);
            });

            Assert.AreEqual(count, w.Read());
            CollectionAssert.AreEquivalent(expected, actual);
        }
    }

    [TestCategory("Channels")]
    [TestMethod]
    public virtual void SyncSelect()
    {
        int expected = 3;

        using (IChannel c0 = new Channel())
        using (IChannel c1 = new Channel())
        using (IChannel c2 = new Channel())
        {
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(Timeblok);
                c0.Write(expected);
            });
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(2* Timeblok);
                c1.Write(expected);
            });
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(3* Timeblok);
                c2.Write(expected);
            });

            IChannelReader res = c0.SelectWith(c1, c2);
            Assert.AreEqual(c0, res);
            Assert.AreEqual(expected, res.Read());
        }
    }

    [TestCategory("Channels")]
    [TestMethod]
    public virtual void SyncBarrier()
    {
        int expected = 3;

        using (IChannel c0 = new Channel())
        using (IChannel c1 = new Channel())
        using (IChannel c2 = new Channel())
        {
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(Timeblok);
                c0.Write(expected);
            });
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(2* Timeblok);
                c1.Write(expected);
            });
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(3* Timeblok);
                c2.Write(expected);
            });

            IEnumerable> res = c0.BarrierWith(c1, c2);
            CollectionAssert.AreEquivalent(new IChannelReader[] { c0, c1, c2 }, res.ToArray());
            foreach (IChannelReader item in res)
            {
                Assert.AreEqual(expected, item.Read());
            }
        }
    }

    //TEST: flaky
    [TestCategory("Channels")]
    [TestMethod]
    public virtual void ConcurrentReaders()
    {
        int count = 2000;
        int r0 = 0;
        int r1 = 0;

        using (IChannel c = new Channel())
        using (IChannel w0 = new Channel())
        using (IChannel w1 = new Channel())
        {
            Task.Factory.StartNew(() =>
            {
                foreach (int item in c.Enumerate())
                {
                    r0++;
                }
                w0.Write(r0);
            });
            Task.Factory.StartNew(() =>
            {
                foreach (int item in c.Enumerate())
                {
                    r1++;
                }
                w1.Write(r1);
            });

            for (int i = 0; i < count; i++)
            {
                c.Write(i);
            }
            c.Close();

            Assert.AreEqual(count, w0.Read() + w1.Read());
            Assert.IsTrue(r0 > 0);
            Assert.IsTrue(r1 > 0);
            //Assert.AreEqual(0.5, r0 / (double)count, 0.2);
            //Assert.AreEqual(0.5, r1 / (double)count, 0.2);
        }
    }

    [TestCategory("Channels")]
    [TestMethod]
    public virtual void SubscribedReaders()
    {
        int count = 10;
        int r0 = 0;
        int r1 = 0;

        using (ISubscribableChannel c = new SubscribableChannel())
        using (IChannel w0 = new Channel())
        using (IChannel w1 = new Channel())
        {

            Task.Factory.StartNew((object rd) =>
            {

                foreach (int item in ((IChannelReader)rd).Enumerate())
                {
                    r0++;
                }
                w0.Write(r0);
            }, c.Subscribe());

            Task.Factory.StartNew((object rd) =>
            {
                foreach (int item in ((IChannelReader)rd).Enumerate())
                {
                    r1++;
                }
                w1.Write(r1);
            }, c.Subscribe());

            for (int i = 0; i < count; i++)
            {
                c.Write(i);
            }
            c.Close();

            Assert.AreEqual(2 * count, w0.Read() + w1.Read());
            Assert.AreEqual(count, r0);
            Assert.AreEqual(count, r1);
        }
    }

About

Framework to enable CSP (Communicating sequential processes) for process synchronization

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages