Saturday, June 13, 2009

To the Barrier!

This post starts the series of .Net Framework 4.0 and C# 4.0 new features reviews. Since I working a lot with concurrency, I choose to start from System.Threading base class library.  Framework 4.0 will contain many useful threading tools, one of them is Barrier class.

Overview

Assume that you have to implement algorithm which can be divided into series of independent phases where result  of each will be used by next one. That means next algorithm phase can not be started before previous one is finished. These days almost every desktop have at least two cores, so it can be good idea to add concurrency to phase computation. If this scenario looks familiar, you will be glad to hear that now is will be pretty easy to synchronize between concurrent phases by using Barrier class.

Some Code

Next code snippet contains Barrier usage example. Here barrier is used to synchronize between three worker threads. In constructor it is possible to specify how much participants barrier will synchronize  and provide handler that will be executed after each phase is completed. When phase is completed worker signals to the barrier and waits until all workers are done. When number of phases worker have to participate is over it is possible to notify barrier that worker is no longer participating by calling RemoveParticipant method.




public class WorkerInfo
{
    public int WorkTime { get; set; }
    public int ParticipiantPhaces { get; set; }
    public string Name { get; set; }
    public Barrier Barrier { get; set; }
}

public class BarrierTest
{
    public void Test()
    {
        ManualResetEventSlim ev = new ManualResetEventSlim(false);

        Barrier barrier = new Barrier(3, b =>
                                            {
                                                Console.WriteLine("Phase {0} completed", b.CurrentPhaseNumber);
                                                if (b.CurrentPhaseNumber >= 3) ev.Set();
                                            });

        ThreadPool.QueueUserWorkItem(Worker, new WorkerInfo
        {
            WorkTime = 400,
            Name = "First",
            ParticipiantPhaces = 4,
            Barrier = barrier
        });

        ThreadPool.QueueUserWorkItem(Worker, new WorkerInfo
        {
            WorkTime = 600,
            Name = "Second",
            ParticipiantPhaces = 3,
            Barrier = barrier
        });

        ThreadPool.QueueUserWorkItem(Worker, new WorkerInfo
        {
            WorkTime = 500,
            Name = "Third",
            ParticipiantPhaces = 2,
            Barrier = barrier
        });

        // No direct way to syncronize with barrier
        // It may be good idea to add barrier.WaitForZeroParticipiants(timeout)
        ev.Wait();

        Console.ReadLine();
    }

    private void Worker(object state)
    {
        WorkerInfo info = state as WorkerInfo;

        for (int i = 0; i < info.ParticipiantPhaces; i++)
        {
            // Do the work
            Thread.Sleep(info.WorkTime);

            Console.WriteLine("{0} done.", info.Name);

            info.Barrier.SignalAndWait();
        }

        info.Barrier.RemoveParticipant();
    }
}




Console Output

barrier_out

OK, phases are separated and workers are synchronized.

Wish List

It can be good idea to add method to wait until all participants will finish and eliminate ManualResetEvent usage.

No comments:

Post a Comment