Saturday, 29 September 2012

C# Synchronization

Here are four examples of synchronization, firing three pieces of work and blocking until any of the three complete:

  • Tasks
  • ManualResetEvents with a WaitHandle
  • ManualResetEvent
  • Monitor Wait and Pulse

image_thumb[3]

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Synchronisation
{
internal class Program
{
private static void Main(string[] args)
{
new TaskWaitAnyExample().Execute();
new ManualResetEventWithWaitHandle().Execute();
new ManualResetEventExample().Execute();
new MonitorWaitAndPulse().Execute();
}
}

public abstract class Example
{
protected string name = "Example";

public abstract void Execute();

protected void MethodA()
{
Console.WriteLine("{0}: Entering MethodA", name);
Thread.Sleep(20000);
Console.WriteLine("{0}: Exiting MethodA", name);
}

protected void MethodB()
{
Console.WriteLine("{0}: Entering MethodB", name);
Thread.Sleep(10000);
Console.WriteLine("{0}: Exiting MethodB", name);
}

protected void MethodC()
{
Console.WriteLine("{0}: Entering MethodC", name);
Thread.Sleep(1000);
Console.WriteLine("{0}: Exiting MethodC", name);
}
}

public class TaskWaitAnyExample : Example
{
public override void Execute()
{
name = "TaskWaitAnyExample";
Console.WriteLine("{0} (from .NET 4.0):", name);

var taskA = Task.Factory.StartNew(MethodA);
var taskB = Task.Factory.StartNew(MethodB);
var taskC = Task.Factory.StartNew(MethodC);

Console.WriteLine("Waiting for one task to finish");
Task.WaitAny(taskA, taskB, taskC);
Console.WriteLine("Signal received, time to move on{0}", Environment.NewLine);
}
}

public class ManualResetEventWithWaitHandle : Example
{
public override void Execute()
{
name = "ManualResetEventWithWaitHandle";
Console.WriteLine("{0} (from .NET 1.1):", name);

WaitHandle[] waitHandles = new WaitHandle[]
{
new ManualResetEvent(false),
new ManualResetEvent(false),
new ManualResetEvent(false)
};

ThreadPool.QueueUserWorkItem(o => { MethodA(); ((ManualResetEvent)waitHandles[0]).Set(); });
ThreadPool.QueueUserWorkItem(o => { MethodB(); ((ManualResetEvent)waitHandles[1]).Set(); });
ThreadPool.QueueUserWorkItem(o => { MethodC(); ((ManualResetEvent)waitHandles[2]).Set(); });

Console.WriteLine("Waiting for one signal that one work item has finished");
WaitHandle.WaitAny(waitHandles);
Console.WriteLine("Signal received, time to move on{0}", Environment.NewLine);
}
}

public class ManualResetEventExample : Example
{
private readonly ManualResetEvent manualResetEvent = new ManualResetEvent(false);

public override void Execute()
{
name = "ManualResetEvent";
Console.WriteLine("{0} (from .NET 1.1):", name);

ThreadPool.QueueUserWorkItem(o => { MethodA(); manualResetEvent.Set(); });
ThreadPool.QueueUserWorkItem(o => { MethodB(); manualResetEvent.Set(); });
ThreadPool.QueueUserWorkItem(o => { MethodC(); manualResetEvent.Set(); });

Console.WriteLine("Waiting for one signal that one work item has finished");
manualResetEvent.WaitOne();
Console.WriteLine("Signal received, time to move on{0}", Environment.NewLine);
}
}

public class MonitorWaitAndPulse : Example
{
readonly object locker = new object();
bool signalSent;

public override void Execute()
{
name = "Monitor Wait and Pulse";
Console.WriteLine("{0} (from .NET 1.1):", name);

ThreadPool.QueueUserWorkItem(o => DoWork(MethodA));
ThreadPool.QueueUserWorkItem(o => DoWork(MethodB));
ThreadPool.QueueUserWorkItem(o => DoWork(MethodC));

Console.WriteLine("Waiting for one signal that one work item has finished");

lock (locker)
while (!signalSent)
Monitor.Wait(locker);

Console.WriteLine("Signal received, time to move on{0}", Environment.NewLine);
}

private void DoWork(Action action)
{
action.Invoke();

lock (locker)
{
signalSent = true;
Monitor.Pulse(locker);
}
}
}
}

1 comment:

  1. Nice
    Would be better to remove line numbers
    Or is it protection against copy-pasting to run your code?

    ReplyDelete