Export (0) Print
Expand All

HOWTO: Stop Multiple Threads

.NET Compact Framework 1.0

Geoff Schwab
Excell Data Corporation

Contributions by Michael Lipp
Microsoft Corporation

October, 2003

Applies to:
   Microsoft® .NET Compact Framework 1.0
   Microsoft Visual Studio® .NET 2003

Download sample.

Summary: This sample demonstrates how to safely shut down a Form with multiple threads running.

Contents

Introduction
Implementation
Conclusion

Introduction

The code in this sample resides in a single Form and demonstrates how to safely shut down a Form with multiple threads running. The Form contains a single button which launches a new thread. Each thread subsequently sits in an infinite loop invoking a counter updating function and waiting for a close request. When the application is closed, the main form waits until all threads are removed before shutting down.

Implementation

The Form defines several global variables. The first, numThreads, specifies the number of threads that have been activated by the thread button and are currently still running. A bool, closeRequested, specifies if the application is attempting to shut down. Finally, counter is a global variable updated by each thread. The purpose of this variable is simply to show that thread(s) are running.

// C#
int numThreads = 0;
bool closeRequested = false;
int counter = 0;

'VB
Private numThreads As Integer = 0
Private closeRequested As Boolean = False
Private counter As Integer = 0

The UpdateCounter method is called by each thread in an infinite loop. Because the function is called by each thread to update the shared global variable counter, there is no functional meaning to the variable other than to show that thread(s) are updating it.

private void UpdateCounter(object o, EventArgs e)
{
    this.OutputLabel.Text =
        String.Format("Threads({0}) Counting: {1}",
        (this.numThreads), this.counter++);
}

Private Sub UpdateCounter(ByVal o As Object, ByVal e As EventArgs)

    Me.OutputLabel.Text = String.Format("Threads({0}) Counting: {1}", _
        Me.numThreads, Me.counter)
    Me.counter += 1

End Sub 'UpdateCounter

The method ThreadProc is the function supplied to the creation of each new thread, i.e., this is the function that will be executed on each thread that is created by the main Form. This function invokes the main thread's UpdateCounter function in a loop while waiting for a request to close the application.

// C#
public void ThreadProc()
{
    // Use the UpdateCount function to update the display
    EventHandler threadDelegate =
        new EventHandler(this.UpdateCounter);

    // Run until the application tries to shutdown
    do
    {
        // Call the counter updating function
    this.Invoke(threadDelegate);
    Thread.Sleep(200);
    }
    while(!this.closeRequested);

    // Close the thread
    this.Invoke(new EventHandler(this.CloseMe));
}

' VB
' Procedure run in each thread.
Public Sub ThreadProc()

    ' Use the UpdateCount function to update the display
    Dim threadDelegate As New EventHandler(AddressOf Me.UpdateCounter)

    ' Run until the application tries to shutdown
    Do

        ' Call the counter updating function
        Me.Invoke(threadDelegate)
        Thread.Sleep(200)

    Loop While Not Me.closeRequested

    ' Close the thread
    Me.Invoke(New EventHandler(AddressOf Me.CloseMe))

End Sub 'ThreadProc

The Form contains a button which is used to create new threads. Every time the button is pressed, a new thread is created and the thread counter, numThreads, is incremented. The number of threads is arbitrarily limited to 10 for this sample.

// C#
private void ThreadButton_Click(object sender, System.EventArgs e)
{
    // Do not allow more than 10 threads (no particular reason)
    if (this.numThreads >= 10)
        return;

    // Display the thread creation status
    this.OutputLabel.Text = String.Format("Creating Thread {0}",
        this.numThreads + 1);

    // Start a new thread and increment the count
    this.numThreads++;
    Thread thread = new Thread(new ThreadStart(this.ThreadProc));
    thread.Start();
}

'VB
Private Sub ThreadButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles ThreadButton.Click

    ' Do not allow more than 10 threads (no particular reason)
    If Me.numThreads >= 10 Then
        Return
    End If

    ' Display the thread creation status
    Me.OutputLabel.Text = _
        String.Format("Creating Thread {0}", Me.numThreads + 1)

    ' Start a new thread and increment the count
    Me.numThreads += 1
    Dim thread As New Thread(New ThreadStart(AddressOf Me.ThreadProc))
    thread.Start()

End Sub 'ThreadButton_Click

Now that all of the code for creating threads is in place we need to handle shutting them down. To accomplish this, the Form utilizes the OnClosing function. In this function, the Form will check if there are any active threads and then set the global variable closeRequested to true to signify to all threads that the application is waiting for them to close. If there are no threads active then the Form closes, otherwise, it cancels the close request. In the case of the latter, this request will be triggered again by the closing of the subsequent threads.

// C#
protected override void OnClosing(CancelEventArgs e)
{
    if (this.numThreads > 0)
    {
        // If there are no secondary threads running then shut down
        // the application
        e.Cancel = true;
        this.OutputLabel.Text = String.Format("Closing Thread {0}",
            this.numThreads + 1);
    }
    else
    {
        // If there are secondary threads running then cancel
        // the application shutdown
        e.Cancel = false;
        this.OutputLabel.Text = "Closing Main Thread";
    }

    // A close request is now pending
    this.closeRequested = true;
}

' VB
Protected Overrides Sub OnClosing(ByVal e As CancelEventArgs)

    If Me.numThreads > 0 Then

        ' If there are no secondary threads running then shut down
        ' the application
        e.Cancel = True
        Me.OutputLabel.Text = String.Format("Closing Thread {0}", _
            Me.numThreads + 1)

    Else

        ' If there are secondary threads running then cancel
        ' the application shutdown
        e.Cancel = False
        Me.OutputLabel.Text = "Closing Main Thread"

    End If

    ' A close request is now pending
    Me.closeRequested = True

End Sub 'OnClosing

The final step in properly shutting down all threads is the CloseMe function. This method will be called by each thread once it detects that the closeRequested member has been set to true. This method decrements the number of active threads and closes the thread down, thus resulting in the closing event being triggered once again on the main thread.

// C#
private void CloseMe(object o, EventArgs e)
{
    // Decrease number of threads and shutdown
    this.numThreads--;
    this.Close();
}

'VB
Private Sub CloseMe(ByVal o As Object, ByVal e As EventArgs)

    ' Decrease number of threads and shutdown
    Me.numThreads -= 1
    Me.Close()

End Sub 'CloseMe

Conclusion

Because it is not possible to abort a thread in the .NET Compact Framework, the application has to do a bit of extra work when shutting down to ensure that it is closed safely. As this example shows, the code is not terribly complicated and primarily involves tracking the number of active threads and setting a globally monitored variable specifying that a close event is waiting.

Show:
© 2014 Microsoft