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);
}
}
}
}

Thursday, 27 September 2012

Test for Generic Type

Useful helper method I found on StackOverflow

using System;
using System.Collections.Generic;

namespace TestForGenericType
{
class Program
{
static void Main(string[] args)
{
var test = new List<string>();
bool result = test.GetType().IsSubclassOfRawGeneric(typeof(List<>));

// result = true
}
}

static class ReflectionUtils
{
public static bool IsSubclassOfRawGeneric(this Type toCheck, Type baseType)
{
while (toCheck != typeof(object))
{
Type cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
if (baseType == cur)
{
return true;
}

toCheck = toCheck.BaseType;
}
return false;
}
}
}

Sunday, 23 September 2012

INPC Parent Child Notification

Here is a simple example of a parent listening to change notification from a child and exposing an aggregate value (or “denormalized” value in database terminology).

The Order (parent) exposes the TotalCost, which is a sum of the Cost properties in OrderLines (child).

image

public class Order : InpcBase
{
private readonly ObservableCollection<OrderLine> orderLines;

public Order()
{
orderLines = new ObservableCollection<OrderLine>();
}

public decimal TotalCost
{
get { return orderLines.Sum(ol => ol.Cost); }
}

public void AddOrderLine(OrderLine orderLine)
{
orderLine.PropertyChanged += orderLine_PropertyChanged;
}

private void orderLine_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Cost") OnPropertyChanged("TotalCost");
}
}

public class OrderLine : InpcBase
{
private decimal cost;
public decimal Cost
{
get { return cost; }
set
{
if (cost == value) return;
cost = value;
OnPropertyChanged("Cost");
}
}
}

public abstract class InpcBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler == null) return;
handler(this, new PropertyChangedEventArgs(name));
}
}