Stopbyte

How to stop a sleeping Background Thread without crushing the program in C#?

Hi,

i’ve been working on a C# project in which i have a Background thread that does some asynchronous tasks at background. the thread is started at window creation and should be stopped (terminated) at the Window Close event, example:

th = new Thread(new ParameterizedThreadStart(th_do_work));
th.Priority = ThreadPriority.AboveNormal;
th.Start(parameter1);
  • that’s the code used to create, initialize and start the background thread, the method th_do_work() is a simple method that takes one parameter.

This is how i terminate (stop) the thread:

private void Form2_Closed(object sender, EventArgs e)
{
    th_stopped = true; // Here we set stopped to true, so the thread stops processing in a smooth way.
    if (th.ThreadState == System.Threading.ThreadState.WaitSleepJoin)
    {
        th.Interrupt();
    }
}

here is my th_do_work() method (thread body method):

private void th_do_work(object arg1)
{
    /* <- The thread does some tasks here (such as accessing files, registry...etc ->*/
   
    Thread.sleep(long_interval);
    
    // Then checks for stopped flag.
    if (th_stopped) return; // stop nicely.
    
    /* <- The thread does some *other* tasks here (such as accessing files, registry...etc ->*/
   
    Thread.sleep(long_interval);
 
    // Then checks for stopped flag again..
    if (th_stopped) return; // stop nicely.
    
    /* <- The thread does some other finalisation tasks -> */
}

The long interval thread sleeps are critical so can’t remove them, but when stopping the thread i get an exception and the entire program crushes, can you please suggest something fast?

thnks

1 Like

In .NET framework if a thread is terminated/interrupted through the Thread.Interrupt() method (or other alternatives); windows will raise a ThreadInterruptedException Exception. so you can easily trap for that exception using simple try..catch statement.

1 Like

You can add a try catch around all of your th_do_work() method or only around the Thread.Sleep(interval) statements in your function, they will both behave almost the same, but i prefer the first approach as that will also handle any internal sleeps in your other inside function calls within your method th_do_work().

##Here is the first approach:

private void th_do_work(object arg1)
{
    try 
    {
        /* <- The thread does some tasks here (such as accessing files, registry...etc ->*/
       
        Thread.sleep(long_interval);
        
        // Then checks for stopped flag.
        if (th_stopped) return; // stop nicely.
        
        /* <- The thread does some *other* tasks here (such as accessing files, registry...etc ->*/
       
        Thread.sleep(long_interval);
     
        // Then checks for stopped flag again..
        if (th_stopped) return; // stop nicely.
        
        /* <- The thread does some other finalisation tasks -> */
    }
    catch (ThreadInterruptedException ex)
    {
        // if execution reached here, that means it was interrupted by your stop button.
        MessageBox.Show("Cancelled", "Operation cancelled by user.");
        return;
    }
}

##Here is the second Approach:

private void th_do_work(object arg1)
{
    /* <- The thread does some tasks here (such as accessing files, registry...etc ->*/
    try 
    {
        Thread.sleep(long_interval);
    }
    catch (ThreadInterruptedException ex)
    {
        goto interrupted;
    }
    
    // Then checks for stopped flag.
    if (th_stopped) return; // stop nicely.
    
    /* <- The thread does some *other* tasks here (such as accessing files, registry...etc ->*/
       
    try 
    {
        Thread.sleep(long_interval);
    }
    catch (ThreadInterruptedException ex)
    {
        goto interrupted;
    }
    
    // Then checks for stopped flag again..
    if (th_stopped) return; // stop nicely.
    
    /* <- The thread does some other finalisation tasks -> */
    return;
        
interrupted:
    // if execution reached here, that means it was interrupted by your stop button.
    MessageBox.Show("Cancelled", "Operation cancelled by user.");
    return;
 
}

hope that helps :slight_smile: