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?
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.
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;
}