Wednesday, October 05, 2005

Event raising issue

Few days back I was going thru an article on event raising in .NET environment and came accords a question " what is best the practice of raising event in multiple thread application" , let me illustrate with an example ...

say I have an delegate < public delegate void MyDelegate( Object sender, EventArgs e ); >
and an event < public event MyDelegate MyEvent; > inside a class named TestClass
I am raising event from a routine named RaiseEvent (Let me write the code snippet for this routine )

public void RaiseEvent()
{
if( MyEvent != null )
{
EventArgs e = new EventArgs();
MyEvent( this, e );
}
}

The above code will work fine in single thread environment, consider the following situation ... there are multiple threads which are using MyEvent( and there is single instance of TestClass is shared among all the threads ) , so it may happen( hypothetically ) when one thread is calling MyEvent( this, e ) another thread is removing the registered delegate from the MyEvent, have a look at the following figure ....

thread1 ...
action 1 : objTestClass.MyEvent -= new MyDelegate(objTestClass_MyEvent); ( removing the registered delegate from the MyEvent )

thread2 ...
action 1: if( MyEvent != null )
action 2: MyEvent( this, e );

If CPU switching between threads happen like the following, then there is a problem ..

thread2 -> action 1
thread1 -> action 1
thread2 -> action2 ( will raise an exception since the registered delegate from the MyEvent is removed ).

How to solve this issue .. firstly, I think we should not allow any thread to remove the registered delegate, if it is inevitable then how about the next solution
MyDelegate tmpMyEvent = MyEvent;

if( tmpMyEvent != null )
{
EventArgs e = new EventArgs();
tmpMyEvent( this, e );
}

This will solve the issue( am I correct ? ). I was looking for some MS documentation in this regards, but in vain , anybody has some comments to add .. please do.( thanks in advance -:) )











Sunday, October 02, 2005

ByVal and ByRef

We all deal with passing parameter ByVal and ByRef and as we all know that if we pass a variable byval to a routine and if the called routine changes the variable value, it does not reflect in the caller routine, opposite happen in case of byref.

But what happen in case of passing reference type as byval or byref … let us consider the following example..

I have a class named TestClass and which have a public property Name , then all I will do in a win form is create 2 routines which will takes instance of this class as a parameter, first one will take as byval, second one as byref.

private void UpdateTestClassName( TestClass objTestClass )
{
objTestClass.Name = "Neo";
}

private void UpdateTestClassName( ref TestClass objTestClass )
{
objTestClass.Name = "Neo";
}

Then I will add 2 buttons( ByVal and ByRef ) on the form and in the click event of one of them will call the both routines. Like this …

private void btnByVal_Click(object sender, System.EventArgs e)
{
TestClass objTestClass = new TestClass();
objTestClass.Name = "Palb";
Console.WriteLine( objTestClass.Name );
UpdateTestClassName( objTestClass );
try
{
Console.WriteLine( objTestClass.Name );
}
catch( System.NullReferenceException ex )
{
Console.WriteLine( ex.Message );
}
}

private void btnByRef_Click(object sender, System.EventArgs e)
{
TestClass objTestClass = new TestClass();
objTestClass.Name = "Palb";
Console.WriteLine( objTestClass.Name );
UpdateTestClassName( objTestClass );
try
{
Console.WriteLine( objTestClass.Name );
}
catch( System.NullReferenceException ex )
{
Console.WriteLine( ex.Message );
}
}

If we click on ByVal button the output will be following
Palb
Neo

And if we click on the ByRef button the output will be following ..
Palb
Neo

So it seems byVal and byRef behave in same manner in case of Reference type , why is it happening … let us look at what happen inside ..

Data for Reference types is stored on the heap and a pointer (which points to the data on the heap) is created on the stack, whenever an instance of reference type is created the pointer is returned back and is used to manipulate the data on the stack. Hence TestClass objTestClass = new TestClass(); actually returns back the pointer.

Now when this pointer is passed by val, all we are doing is duplicating the pointer but it still points to the same memory on the heap and hence any manipulation done to the object in the called method will manipulate the same data to which original TestClass pointer was pointing. In case of passing by ref, the original pointer itself is passed to the called function,

Now some more interesting facts , let us add one more line to the UpdateTestClassName routines( both byVal and byRef )
objTestClass = null;

Now guess what will the put out …
By Val click will be same , but By Ref click will be
Palb
Object reference not set to an instance of an object.

As we in case of ByRef we pass the original pointer hence if we set objTestClass = null, the original pointer get destroyed( in case of byVal the original pointer still exists, hence it shows the updated value in heap ), hence we will get an NullReferenceException.
Isn’t it interesting ??