Friday, July 3, 2009

Tasks, TaskScheduler and new Thread Pool in .Net 4.0

Another item in list of newly added threading primitives in .Net 4.0 is a Task. It represents asynchronous operation which execution is controlled by TaskScheduler. In this post I will try to analyze task and scheduler capabilities.

OVERVIEW

First of all lets look how can we use Task. For this propose I changed some code from previous post to use Task instead of thread pool mechanism:





  1. public void TestBarrier()
  2. {
  3. Barrier barrier = new Barrier(3, b =>
  4. {
  5. Console.WriteLine("Phase {0} completed", b.CurrentPhaseNumber);
  6. });
  7. Task task1 = Task.Factory.StartNew(() => Worker(new WorkerInfo { WorkTime = 400, Name = "First", ParticipiantPhaces = 4, Barrier = barrier }));
  8. Task task2 = Task.Factory.StartNew(() => Worker(new WorkerInfo { WorkTime = 600, Name = "Second", ParticipiantPhaces = 3, Barrier = barrier }));
  9. Task task3 = Task.Factory.StartNew(() => Worker(new WorkerInfo { WorkTime = 500, Name = "Third", ParticipiantPhaces = 2, Barrier = barrier }));
  10. Task.WaitAll(task1, task2, task3);
  11. Console.WriteLine("Barrier done.");
  12. }




Lines 8-10 creates and schedules three tasks each of them will execute Worker function. First difference is that task is initialized by Action or Func<TResult> delegates in opposite to thread pool WaitCallBack delegate. It means that there are two types of tasks: first one initialized by Action that does it work and does not returns any values, and another one initialized by Func<TResult> that will return some value. Thus, if task is initialized by Func<TResult> new instance of Task<TResult> is created which contains Result property. When task is finished value returned by Func delegate will be stored in the task and can be obtained from Result property. Both types of tasks contains Exception property that will store an exception thrown by the worker delegates. If exception is not thrown Exception property will return null.

Synchronization

Next important tasks feature is synchronization. Task contains two static methods WaitAll and WaitAny that acts exactly like WaitHandle.WaitAll and WaitHandle.WaitAny. That means that there is built-in tasks synchronization mechanism. Line 12 shows how it is simple to block until all executed functions are finished.

Scheduling

So, let’s understand what happens when task is started, by StartNew function for example. Task execution is controlled by TaskScheduler associated to current synchronization context. Actually task scheduler is an abstract class and it is up to its implementation to decide how task will be executed.

protected internal abstract void QueueTask(Task task)


When new task is started task scheduler QueueTask method is called. Now scheduler have to decide what to do. Default scheduler will execute tasks in same manner as thread pool did it before. But now task scheduler can be replaced by user implementation. There is good sample in MSDN, showing dedicated thread pool implementation which executes all queued tasks turn by turn in one thread.



Conclusion



Task provides very comfortable and tunable parallel programming mechanism. However it is important to note that user can’t assume that Task he executes will really run in parallel. That's why it is very bad idea to block task execution in any way, i.e. lock or wait. The best practice to use task for any independent operation that doesn’t need to access any shared resources.

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.

Friday, June 12, 2009

Visual Studio 2010 beta 1

Today I downloaded VS2010 beta 1.

Installation process takes about 3 hours on my Lenovo T60 (3GB, dual core) and it requires to restart the system about 4 times.

OK, it is the first look on VS2010 IDE.



It runs pretty fast for beta software. After clicking on almost every button it still running... :)

OK, so it is the time to open new project on .Net Framework 4.0

In next posts I will cover new .Net 4 features with code samples.

Tuesday, June 9, 2009

Hello, World!

Hello, World!


It's my first post! Finally, I decided to start blogging on profession related things. And since my day by day work is writing in .Net /C# I would like to share with you my experience.


I hope this blog will be regular and I am looking forward to discuss any .Net related issues here.


See you!