Sunday, February 17, 2008

Use of EventWaitHandle

Ever faced a problem where the application does not close even after the main form is closed? If yes, one reason could be the threads you are using. If you are using some threads that run a infinite loop which perform some operation at some intervals with a interval of some minutes or more, and you are using Thread.Sleep(), read further.

Consider the following class code snippet.

public class ThreadTest

{

Thread thSettingsMonitor = null;

bool _stopTimeOutProcessing = false;

public override string ToString()

{

return "Thread running state is : " + this._stopTimeOutProcessing.ToString();

}

public void Start()

{

thSettingsMonitor = new Thread(new ThreadStart(ReloadSettings));

thSettingsMonitor.Start();

Debug.WriteLine("~~~ Starting the thread. Hash code: " + this.GetHashCode().ToString());

}

public void Stop()

{

try

{

//set the variable so that the loop breaks and thread terminates

_stopTimeOutProcessing = true;

}

catch { }

}

private void ReloadSettings()

{

while (!_stopTimeOutProcessing)

{

try

{

//do some operation in the thread

//Mimic by a sleep of 2 seconds

Thread.Sleep(2000);

//wait for 5 minutes

Debug.WriteLine("~~~ reload thread waiting on sleep for 5 min. Hash code: " + GetHashCode().ToString());

Thread.Sleep(30000);

Debug.WriteLine("~~~ Sleep period completed");

}

catch (Exception ex)

{

Debug.WriteLine(ex);

}

}

}

}

Now in a windows application form write the following code

private ThreadTest othTest = new ThreadTest();

private void button1_Click(object sender, EventArgs e)

{

//Start the reloadsettings thread

othTest.Start();

}

private void FrmTest_FormClosing(object sender, FormClosingEventArgs e)

{

othTest.Stop();

}

Run the code, click on the button so that the thread starts running. Try closing the form. Note that the form closes but the .net IDE does not breaks until some time. This means that some code is still executing. Click on the pause button of .net IDE to see which code is running. You will notice that the thread code Thread.Sleep(30000); is still executing.

Now try the updated code.

public class ThreadTest

{

Thread thSettingsMonitor = null;

bool _stopTimeOutProcessing = false;

private EventWaitHandle _exitEvent = new EventWaitHandle(false, EventResetMode.ManualReset);

public override string ToString()

{

return "Thread running state is : " + this._stopTimeOutProcessing.ToString();

}

public void Start()

{

thSettingsMonitor = new Thread(new ThreadStart(ReloadSettings));

thSettingsMonitor.Start();

Debug.WriteLine("~~~ Starting the thread. Hash code: " + this.GetHashCode().ToString());

}

public void Stop()

{

try

{

//set the variable so that the loop breaks and thread terminates

_stopTimeOutProcessing = true;

if (_exitEvent != null)

{

Debug.WriteLine("~~~ Signalling the timeout thread. Hash code: " + this.GetHashCode().ToString());

_exitEvent.Set();

Debug.WriteLine("~~~ Signalling the timeout thread done. Hash code: " + this.GetHashCode().ToString());

}

}

catch { }

}

private void ReloadSettings()

{

while (!_stopTimeOutProcessing)

{

try

{

//do some operation in the thread

//Mimic by a sleep of 2 seconds

Thread.Sleep(2000);

//wait for 5 minutes

Debug.WriteLine("~~~ reload thread waiting on eventwait object for 5 min. Hash code: " + GetHashCode().ToString());

_exitEvent.WaitOne(300000, true);

Debug.WriteLine("~~~ done waiting or the eventwait object was signaled");

}

catch (Exception ex)

{

Debug.WriteLine(ex);

}

}

}

}

Run the code and note the difference. This time the application closes immediately.

Let’s understand what was different.

private EventWaitHandle _exitEvent = new EventWaitHandle(false, EventResetMode.ManualReset);

Here we created a thread synchronization object with initial state as non signaled and mode as manual.

Instead of Thread.Sleep(2000); we have now used _exitEvent.WaitOne(300000, true); this instructs the thread to wait for 5 minutes (30000 msec) and exit the wait before the time is elapsed if the event object is signaled.

During form close we have used _exitEvent.Set();. This code signals the event object. When the event object is signaled the thread comes out of wait immediately even before the wait time is completed. The EventWaitHandle is a versatile object when it comes to thread synchronization. Explore it if you are writing multi threaded applications.

PS: The above problem can be easily worked out in normal scenario by setting the thread as a background thread. The only problem it will have is it will be aborted immediately during application close.


Happy coding!