- XP 64 bit can leverage all 4GB of RAM which allows me to run 4/5 instances of VS.NET, SQL Server, Outlook, Firefox and a dozen of background applications without any noticeable performance degradation.
- XP 64 bit shares core components with Windows Server 2003 which would explain its great performance and reliability.
- XP 64 bit comes with IIS 6.0. I suppose I don't have to explain why this is big. If my point is not clear to you, just compare IIS 5.1 and IIS 6.0 and you will immediately understand what I'm talking about.
Saturday, 7 June 2008
Windows XP 64 bit - a relatively unknown but great operating system
Thursday, 29 May 2008
WeakEvent - you wish it was here
When you define an event you don't have to write add/remove methods on your own because C# compiler generates them automatically. Basically the following code snippet:
public event EventHandler <EventArgs> MyEvent;
is just "syntactic sugar" that C# compiler transforms to much more verbose form. You can find detailed description of this process in CLR via C# by Jeffrey Richter. From our perspective the most important thing is that we can overwrite the default behavior of the compiler and inject our own implementation of Add and Remove methods in a way that is completely transparent to subscribers. SomeClass and Subscriber classes show how it can be done. Don't worry about WeakEvent<T> class as it will be explained later.
public class SomeClass
{
private WeakEvent <EventArgs> myWeakEvent;
public event EventHandler <EventArgs> MyWeakEvent
{
add
{
myWeakEvent.Add(value);
}
remove
{
myWeakEvent.Remove(value);
}
}
private void SomeMethodThatNeedsToRiseMyWeakEvent()
{
OnMyWeakEvent(new EventArgs());
}
protected void OnMyWeakEvent(EventArgs args)
{
myWeakEvent.Invoke(args);
}
}
public class Subscriber
{
private SomeClass someClass;
public Subscriber()
{
someClass = new SomeClass();
someClass.MyWeakEvent += Method;
}
private void Method(object sender, EventArgs e)
{
}
}
Add and Remove methods take a delegate as the input parameter. Every .NET delegate is an object with 2 properties. One of them is a reference to the target of the delegate(the object the delegate will be called on) and the second one is a description of the method which is provided as an instance of System.Reflection.MethodInfo class. Static delegates have the target property set to null. The target field is the root of all evil as it keeps the subscriber alive(it is a strong reference to the object the delegate will be called on). Fortunately .NET framework provides a class that can act as man in the middle between the method and its target which lets us break the direct link between them.
The class that makes it possible is called (no surprise) System.WeakReference. An instance of System.WeakReference class keeps a weak reference(instead of strong) to the object that is passed to its constructor. The weak reference can be transformed into the strong reference by accessing its Target property and storing its value in an ordinary variable. In this way we resurrect the object. If the object is already garbage-collected then the property returns null. All aforementioned functionality is encapsulated in a custom class that I called WeakDelegate.
internal class WeakDelegate
{
private WeakReference target;
private MethodInfo method;
public object Target
{
get
{
return target.Target;
}
set
{
target = new WeakReference(value);
}
}
public MethodInfo Method
{
get { return method; }
set { method = value; }
}
}
WeakEvent<T> is a class that takes advantage of WeakDelegate class to solve the problem outlined in the first paragraph. Its below implementation is rather straightforward but 2 pieces of code might need some explanation. The first one is inside Invoke method. Internally we store instances of WeakDelegate class which means that we can not invoke them directly and every time one of them needs to be executed we have to assemble an instance of System.Delegate class. I don't know if the way the code creates delegates is the fastest one but I measured the execution time of that statement and the average time was 0.005384 ms per delegate which is fast enough for me. The second one is related to the fact that the locking is done in a way that prevents threads from waiting forever. If a thread can't enter the critical section within 15 seconds then it throws an exception. The rationale behind that approach is explained here.
public class WeakEvent <T> where T : EventArgs
{
private readonly List <WeakDelegate> eventHandlers;
private readonly object eventLock;
public WeakEvent()
{
eventHandlers = new List <WeakDelegate>();
eventLock = new object();
}
public void Invoke(T args)
{
ExecuteExclusively(delegate
{
for (int i = 0; i < eventHandlers.Count; i++)
{
WeakDelegate weakDelegate = eventHandlers[i];
// don't move this line to the ELSE block
//as the object needs to be resurrected
Object target = weakDelegate.Target;
if (IsWeakDelegateInvalid(target, weakDelegate.Method))
{
eventHandlers.RemoveAt(i);
i--;
}
else
{
Delegate realDelegate = Delegate.CreateDelegate(typeof(EventHandler <T>),
target, weakDelegate.Method);
EventHandler <T> eventHandler = (EventHandler <T>)realDelegate;
eventHandler(this, args);
}
}
});
}
public void Remove(EventHandler <T> value)
{
ExecuteExclusively(delegate
{
for (int i = 0; i < eventHandlers.Count; i++)
{
WeakDelegate weakDelegate = eventHandlers[i];
Object target = weakDelegate.Target;
if (IsWeakDelegateInvalid(target, weakDelegate.Method))
{
eventHandlers.RemoveAt(i);
i--;
}
else
{
if (value.Target == target && value.Method == weakDelegate.Method)
{
eventHandlers.RemoveAt(i);
i--;
}
}
}
});
}
public void Add(EventHandler <T> value)
{
ExecuteExclusively(delegate
{
RemoveInvalidDelegates();
WeakDelegate weakDelegate = new WeakDelegate();
weakDelegate.Target = value.Target;
weakDelegate.Method = value.Method;
eventHandlers.Add(weakDelegate);
});
}
private void RemoveInvalidDelegates()
{
for (int i = 0; i < eventHandlers.Count; i++)
{
WeakDelegate weakDelegate = eventHandlers[i];
if (IsWeakDelegateInvalid(weakDelegate))
{
eventHandlers.RemoveAt(i);
i--;
}
}
}
private void ExecuteExclusively(Operation operation)
{
bool result = Monitor.TryEnter(eventLock, TimeSpan.FromSeconds(15));
if (!result)
{
throw new TimeoutException("Couldn't acquire a lock");
}
try
{
operation();
}
finally
{
Monitor.Exit(eventLock);
}
}
private bool IsWeakDelegateInvalid(WeakDelegate weakDelegate)
{
return IsWeakDelegateInvalid(weakDelegate.Target, weakDelegate.Method);
}
private bool IsWeakDelegateInvalid(object target, MethodInfo method)
{
return target == null && !method.IsStatic;
}
}
You might have noticed that there is some housekeeping going on whenever one of Add, Remove or Invoke methods is called. The reason why we need to do this is that WeakEvent<T> keeps a collection of WeakDelegate objects that might contain methods bound to objects(targets) that have been garbage-collected. In other words we need to take care of getting rid of invalid delegates on our own. Solutions to this problem can vary from very simple to very sophisticated. The one that works in my case basically scans the collection of delegates and removes invalid ones every time a delegate is added, removed or the event is invoked. It might sound like overkill but it works fine for events that have around 1000-5000 subscribers and it's very simple. You might want to have a background thread that checks the collection every X seconds but then you need to figure out what is the value of X in your case. You can go even further and keep the value adaptive but then your solution gets even more complicated. In my case the simplest solutions works perfectly fine.
Hopefully this post will save someone an evening or two :).
Monday, 28 April 2008
Machines are predictable, people are not
I suppose we would all agree with that and that's why smart people try to develop processes to make us more predictable. On the other hand nobody likes being constrained by anything and especially a process. Some people call this kind of lack of structure freedom, some call it chaos :). From my experience a bit of process might actually help a lot whereas a complete lack of it leads sooner or later to a disaster. Scrum is one of the approaches that let people develop software in a predictable way and that's the topic of the next MTUG event (29th April) that I'm not going to miss. See you there.
Wednesday, 16 April 2008
Never ever synchronize threads without specifying a timeout value
- CLR, Concurrent Programming : Joe Duffy - Microsoft
- CLR : CLR Via C# - Jeffrey Richter - Wintellect
- Debugging: Tess - Microsoft
- Minimize locking - Basically lock as little as possible and never execute code that is not related to a given shared resource in its critical section. The most problems I've seen were related to the fact that code in a critical section did more then it was absolutely needed.
- Always use timeout - Surprisingly all synchronization primitives tend to encourage developers to use overloads that never time out. One of the drawbacks of this approach is the fact that if there is a problem with a piece of code then an application hangs and nobody has an idea why. The only way to figure that out is to create a dump of a process (if you are lucky enough and the process is still hanging around) and debug it using Debugging Tools for Windows. I can tell you that this is not the best way of tackling production issues when every minute matters. But if you use only API that lets you specify a timeout then whenever a thread fails to acquire a critical section within a given period of time it can throw an exception and it's immediately obvious what went wrong. DefaultPreferred
Monitor.Enter(obj)Monitor.TryEnter(obj, timeout)WaitHandle.WaitOne()WaitHandle.WaitOne(timeout, context)
The same logic applies to all classes that derive from WaitHandle: Semaphore, Mutex, AutoResetEvent, ManualResetEvent. - Never call external code when in a critical section - Calling a piece of code that was passed to a critical section handler from outside is a big risk because there is always a good chance that at the time the code was designed nobody even thought that it might be run in a critical section. Such code might try to execute a long running task or to acquire another critical section. If you do something like that you simply ask for trouble :)
Wednesday, 26 March 2008
MIX summary in Dublin
It looks like there will be a micro MIX like event in Dublin in May - http://visitmix.com/2008/worldwide/. It might be interesting.
Sunday, 24 February 2008
There is no perfect job
I suppose we all know that there are always some "ifs" and "buts". Edge Pereira wrote a blog post about a few of them that are related to human-human interaction. If I had to choose a single sentence from his post I would go for this one: "if an employee does not know the reason of his daily work, he will never wear the company's jersey". Needles to say I totally agree with the whole post.
Friday, 15 February 2008
ReSharper 4 - nightly builds available at last
At this stage I nearly refuse writing code without ReSharper. I know it's bad but that's not the worst addiction ever :). Fortunately, JetBrians decided to release nightly builds of ReSharper 4 to public. Sweet.