Blocking until a Thread Finishes


The desktop version of the .NET Framework features a method called Thread.Join() . Given a thread called l_Thread , if another thread calls l_Thread.Join() , then the other thread blocks until l_Thread terminates. The .NET Compact Framework does not support Thread.Join() .

One way to wait for another thread to die is to use a busy wait. For example, the thread method might update the Boolean class member m_Alive to false as it exits. Another thread can sit and wait for the first thread to finish by writing code that looks like this:

 
 C# // Wait for another thread to set m_Alive to false while (m_Alive) { } VB ' Wait for another thread to set m_Alive to false while (m_Alive = True) End While 

This would be a very bad idea because the act of waiting consumes CPU cycles. The thread that is waiting continuously checks the m_Alive variable, using CPU resources that could be used for meaningful processing. Additionally, running such tight loops can slow down applications noticeably.

The right way to have one thread wait for another to finish is in such a way that the waiting thread does not consume CPU cycles. This feature can be realized using Mutex objects. To use this technique, developers must write support for a simulated join into their thread methods . Follow these steps to structure your thread so that other threads can wait for them to finish:

  1. The thread that waits for another thread to finish is referred to as the parent thread . The thread that is being waited for is referred to as the child thread.

  2. In the parent thread, create a new Mutex in a scope such that the parent and child threads can both see it. Pass false into the Mutex constructor so that the parent thread does not initially hold ownership of the Mutex .

  3. Create a Boolean variable, such as m_ThreadRunning , and set it to false in the parent thread.

  4. Start the child thread from the parent thread.

  5. Structure the code run in the child thread so that the first thing it does is call Mutex.WaitOne() to acquire ownership of the Mutex . Immediately after, the child thread sets m_ThreadRunning to true .

  6. The last thing the child thread should do before exiting is to release the Mutex by calling Mutex.ReleaseMutex() .

  7. When the parent thread wants to block until the child is finished, effectively doing a Join() , have the parent loop and wait for m_ThreadRunning to turn true . Make sure to put a sleep statement in the loop to avoid wasting CPU cycles. Usually, this wait will not occur, but there occasionally will be a very short wait because as soon as the child thread starts, it will acquire the Mutex and set m_ThreadRunning to true .

  8. When m_ThreadRunning is true , call Mutex.WaitOne() in the parent thread. The parent will block without consuming any CPU cycles until the child thread has finished.

  9. Call Mutex.ReleaseMutex() from the parent.

The following sample code demonstrates these steps. The code is taken from the sample application JoinDemo.

 
 C# // This is the code that runs in the child thread private void DoSomeWork() {    m_ThreadAliveMutex.WaitOne();    m_isThreadRunning = true;    // Do some work here.  We'll just sleep to simulate work that    // took a while    System.Threading.Thread.Sleep(10000);    // Release the "alive" mutex on thread exit, indicating that    // this thread is dying.    m_ThreadAliveMutex.ReleaseMutex(); } // This is the code that runs in the parent thread // m_isThreadRunning is a bool class member // m_ThreadAliveMutex is a Mutex class member m_isThreadRunning = false; m_ThreadAliveMutex = new System.Threading.Mutex(false); m_threadStart = new System.Threading.ThreadStart(DoSomeWork); m_workerThread = new System.Threading.Thread(m_threadStart); MessageBox.Show("Starting thread and then waiting    for it to finish"); m_workerThread.Start(); // We actually need to know that the thread has started before // we wait for it. while (m_isThreadRunning == false) {    System.Threading.Thread.Sleep(100); } m_ThreadAliveMutex.WaitOne(); m_ThreadAliveMutex.ReleaseMutex(); MessageBox.Show("Worker thread has stopped"); VB Private Sub DoSomeWork()    m_ThreadAliveMutex.WaitOne()    m_isThreadRunning = True    ' Do some work here.  We'll just sleep to simulate work that took a    ' while    System.Threading.Thread.Sleep(10000)    ' Release the "alive" mutex on thread exit, indicating that    ' this thread is dying.    m_ThreadAliveMutex.ReleaseMutex() End Sub ' This is the code that runs in the parent thread ' m_isThreadRunning is a bool class member ' m_ThreadAliveMutex is a Mutex class member m_isThreadRunning = False m_ThreadAliveMutex = New System.Threading.Mutex(False) m_threadStart = New System.Threading.ThreadStart(AddressOf DoSomeWork) m_workerThread = New System.Threading.Thread(m_threadStart) MessageBox.Show("Starting thread and then waiting for it to finish") m_workerThread.Start() ' We actually need to know that the thread has started before ' we wait for it. While (m_isThreadRunning = False)    System.Threading.Thread.Sleep(0) End While ' This is like a join - no CPU cycles consumed while we wait m_ThreadAliveMutex.WaitOne() m_ThreadAliveMutex.ReleaseMutex() MessageBox.Show("Worker thread has stopped") 

Waiting for a Thread: The JoinDemo Application

The JoinDemo application demonstrates the process of simulating a call to Thread.Join() using the .NET Compact Framework. The main thread spins off a child thread, which simulates taking time to do some work by going to sleep for 10 seconds. Meanwhile, the main thread is blocked because it is waiting to acquire a Mutex , as discussed previously.

The JoinDemo sample is located in the folder \SampleApplications\Chapter4 . There are C# and Visual Basic versions of the application.



Microsoft.NET Compact Framework Kick Start
Microsoft .NET Compact Framework Kick Start
ISBN: 0672325705
EAN: 2147483647
Year: 2003
Pages: 206

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net