Showing posts with label Thread. Show all posts
Showing posts with label Thread. Show all posts

Sunday, January 20, 2008

AutoResetEvent Object and Hanged Application

This is something related to a bug which was not so reproduce able , but was seen once a week at least on one of the many test machines. We used to get a "Server busy" dialog box and Switching or Retrying did not do anything. We have to kill the application.

I was accustom to see this dialog when a COM server is busy or is waiting for some resource and usually after some time, Switching or Retrying worked.

Fortunately i got this error on my development machine once and more fortunately i was running a debug build. I paused the program and watched the call stack. The program was waiting on a thread which was in a "Wait or Sleep/Join state". Drilling down more on the thread, it was found that it was one of the our own application thread.

This information gave me a good deal of information on where to look for. I checked the module which created the thread and found that it was created in a user control and the thread was using a AutoResetEvent object. The wait state of the thread as i discovered earlier from call stack was from the Dispose call of the user control. I checked the code to see the places where the AutoResetEvent was closed or signaled. Well the object was not cleaned up/closed in the Dispose call "which was the problem".

The thread was waiting on the AutoResetEvent object and was not allowing the user control to Dispose and hence the application to close.

Learning:
1. Clean up all variables manually, don't rely on GC. GC does a good job, but we screw up our selves thinking GC will take care.
2. Use of thread and windows kernel objects like Mutex, Semaphores etc (thread synch objects) are a double edged sword. Always use them with caution.

Saturday, January 5, 2008

How much a Thread cost you?

I was recently wondering if creating n number of threads will affect the memory usage of an application. I created a sample application which created a thread on a button click to observe the memory usage on each thread creation. The thread proc as such did nothing; I had put a sleep statement in it so that the thread is alive and is using the memory for some time while I am creating some more threads.

I was relaxed to see that the memory usage in task manager rose by just 20K -30 K on each thread creation with an exception that the first thread creation increased the memory by around 1 MB.


Later I started checking Virtual memory usage as well and was shocked to see 1 MB of memory usage on each thread creation! A little goggling revealed that by default each thread is assigned a 1 MB stack! Check out the sample code which prints out the Virtual Memory usage of the test application in debug window on each thread creation.

//code
private static void Somethread()
{
Debug.WriteLine(string.Format("Started thread with thread id {0}", Thread.CurrentThread.ManagedThreadId));
//Print task managers VM Size column
Debug.WriteLine(string.Format("Current VM usage is {0} MB", (Process.GetCurrentProcess().PagedMemorySize64 / (1024 * 1024))));

Thread.Sleep(1000 * 60 * 1); // let the thread live for some time while we create some more threads
Debug.WriteLine(string.Format("----Ended thread with thread id {0}", Thread.CurrentThread.ManagedThreadId));

//Print task managers VM Size column
Debug.WriteLine(string.Format("Current VM usage is {0} MB", (Process.GetCurrentProcess().PagedMemorySize64 / (1024 * 1024))));

}

private void btnCreateThread_Click(object sender, EventArgs e)
{
//Each created thread will be allocated 1 MB of Virtual memory
Thread samplethread = new Thread(Somethread);
samplethread.IsBackground = true;
samplethread.Start();
}

Conclusion: Want to keep a small footprint of the application, think twice before creating a new thread.