How do I abort multiple threads? - c#

In this code, when button1 is clicked twice, it creates 2 separate threads. On one click, it creates a new thread on the heap and field t1 points to the new thread on the heap. When I click button2, it aborts the last thread (which t1 refers to).
How do I abort the other thread?
Thread t1;
ThreadStart ts1;
private void button1_Click(object sender, EventArgs e)
{
ts1 = new ThreadStart(myfunc);
t1 = new Thread(ts1);
t1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
t1.Abort();
}

Well, the OO answer would be to hold a list of threads as a field.
private readonly List<Thread> threads = new List<Thread>();
And to then add the newly constructed thread to the list in the first handler.
var thread = new Thread(myfunc);
thread.Start();
threads.Add(thread);
Then you could iterate through each thread in the second handler, aborting each of them in turn.
foreach(var thread in threads)
thread.Abort();
But I think the most important point here is that there is almost never a good reason to call Thread.Abort.
From the MSDN page:
When a thread calls Abort on itself,
the effect is similar to throwing an
exception; the ThreadAbortException
happens immediately, and the result is
predictable. However, if one thread
calls Abort on another thread, the
abort interrupts whatever code is
running. There is also a chance that a
static constructor could be aborted.
In rare cases, this might prevent
instances of that class from being
created in that application domain. In
the .NET Framework versions 1.0 and
1.1, there is a chance the thread could abort while a finally block is
running, in which case the finally
block is aborted.
The thread that calls Abort might
block if the thread that is being
aborted is in a protected region of
code, such as a catch block, finally
block, or constrained execution
region. If the thread that calls Abort
holds a lock that the aborted thread
requires, a deadlock can occur.
You would be much better off using some form of signalling, such as setting a ManualResetEvent that each thread will poll at perioidic intervals. Alternatively, you could use the BackgroundWorker class that has some support for task-cancellation (call CancelAsync on it, and get the worker threads to test CancellationPending periodically). If you are on .NET 4.0, you can also use the TPL.

I would recommend you to take a look at the built in synchronization primitives such as ManualResetEvent and WaitHandle. You can ask a thread if it's running or not by trying to join the thread with Thread.Join. Aborting a thread should only be done as a last resort if the thread is unresponsive.
Here is an modified example of your code that shows how you can prevent the thread from be restarted before it's been stopped properly.
public partial class MainForm : Form
{
private Thread t1;
private ThreadStart ts1;
private ManualResetEvent t1resetEvent;
public MainForm()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Got a thread?
if (t1 != null) {
if (!t1.Join(0)) {
// The thread seems to be running.
// You have to stop the thread first.
return;
}
}
t1resetEvent = new ManualResetEvent(false);
ts1 = new ThreadStart(MyFunc);
t1 = new Thread(ts1);
t1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
// Got a thread?
if (t1 != null)
{
// Set the reset event so the thread
// knows it's time to stop.
t1resetEvent.Set();
// Give the thread four seconds to stop.
if (!t1.Join(4000)) {
// It did not stop, so abort it.
t1.Abort();
}
}
}
private void MyFunc()
{
// Long running operation...
while (true)
{
// Do someone want us to exit?
if (t1resetEvent.WaitOne(0)) {
return;
}
}
}
}

The others have given the long versions of the answer, however the obvious simple solution is to simply skip recreating the thread object:
public partial class Form1 : Form
{
Thread thread1;
ThreadStart threadStart1;
public Form1()
{
InitializeComponent();
threadStart1 = new ThreadStart(threadTarget);
thread1 = new Thread(threadStart1);
thread1.Name = "Button1 thread";
}
private void button1_Click(object sender, EventArgs e)
{
thread1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
thread1.Abort();
}
private void threadTarget()
{
Console.WriteLine(Thread.CurrentThread.Name);
for (int i = 0; i < 100; i++)
{
Console.WriteLine(i);
Thread.Sleep(500);
}
}
}
However, I would consider reading up on Threading in .NET using one these guides (I'd recommend Joseph Albahari's guide on aborting - the author of C# in a nutshell) rather than use this method, particularly if you're performing IO or database operations which can leave the objects in unexpected states.

Also, have in mind that calling Abort on a Thread is evil. You should stop the thread with a boolean condition or something like that.
Check this:
http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation

Related

Why does Thread.Sleep() freeze the Form?

I try to experiment with Thread.Sleep(). I created basic Windows Forms application with one button.
private void button1_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(DoStuff);
thread1.Start();
for (int i = 0; i < 100000; i++)
{
Thread.Sleep(500);
button1.Text +=".";
}
}
public void DoStuff()
{
//DoStuff
}
When I click my button the DoStuff method works fine, but the GUI freezes and nothing happens. Can someone explain me why?
Thread.Sleep just sleeps the current thread (i.e. stops it from doing anything, such as redrawing, processing clicks etc), which in your case is the UI thread. If you put the Sleep in DoStuff you wouldn't experience the block as you'd be on a separate thread although you wouldn't be able to update button1. Depending on the version of .NET you're using consider using the Task Parallel Library, something like this:
private TaskScheduler _uiScheduler;
public Form1()
{
InitializeComponent();
_uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
}
private void button1_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(DoStuff);
thread1.Start();
// Create a task on a new thread.
Task.Factory.StartNew(() =>
{
for (int i = 0; i < 100000; i++)
{
Thread.Sleep(500);
// Create a new task on the UI thread to update the button
Task.Factory.StartNew(() =>
{ button1.Text += "."; }, CancellationToken.None, TaskCreationOptions.None, _uiScheduler);
}
});
}
To keep the UI active, you need for the main UI thread to service its message pump. It can only do that when it is not handling UI events. In your case the function
private void button1_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(DoStuff);
thread1.Start();
for (int i = 0; i < 100000; i++)
{
Thread.Sleep(500);
button1.Text +=".";
}
}
does not return for around 100000*500 milliseconds. While this event handler is executing, the UI thread is busy. It is executing this event handler. As such it is not able to service the message pump. Hence your application's UI freezes.
For that you better use a Timer but if you want your current code to work you need to add Application.DoEvents(); after you update the button.Label += "."
If you're new to multithreading, I strongly encourage you to look at the Task Parallel Library (TPL). It simplifies threading, and gives you tools to help guarantee callback (continuation) threads occur on the UI thread.
The TPL is in the System.Threading.Tasks namespace.
Update: just seen your comment about .Net v2. TPL was introduced in .NET v3.5 or possibly as late as v4.
EDIT: After programming for a few more years, I now know how terrible of a practice this is. DO NOT DO ANYTHING I SUGGESTED BELOW. It's all crap. A more proper solution would be doing all of your intensive methods async all together. Regardless, don't do what I mention below.
All The methods above do work however, I do recommend just using an async void.
Sleep() just pauses the current thread for int amount of milliseconds, and if your whole program runs off of 1 thread, it'll pause the whole program. Don't quote me on this, I do believe that async creates a new thread specifically for that function.
Below I've included a better sleep function.
To call the function asleep(milliseconds),
replace "milliseconds" with how many milliseconds you wish to sleep for.
Function Code:
public async void asleep(int time){
await Task.Delay(time)
}
Re-arrange code as following
private void button1_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(DoStuff);
thread1.Start();
}
public void DoStuff()
{
for (int i = 0; i < 100000; i++)
{
Thread.Sleep(500);
//Invoke goes here
}
}
Now you run your WORK in a separate thread and release your UI thread for usual work (Drawing related or other work)
NOTE - Now you will need Invoke methods to change Button text , else you will get warning for "Cross-thread operation not valid"
More on Invokes - How to update the GUI from another thread in C#?

c# - How to force closing of background worker that run it own threads

I have wpf application, lets call it A-app. A-app runs asyncronic B-method with a background worker. That B-method is located at a different project, and it creates few threads for the B-method init part.
User can ask to run the B-method and can ask to cancel the run and restart.
The problem is that if it is cancelled in the init time, the background worker, which run the B-method is cancelled, but the threads are not.
Restarting creates more thread that cannot work at the same time as the threads from previous run, and it couse some bugs.
Threads method is mostly waiting.
How can I stop the B-method and also cancel the threads it created?
Is a different AppDomain could help in any way? (and than close the whole app domain?) If yes, that how should it be done?
Is there a better way?
More details:
The B-method runs tests on some devices (could be many). the init of the method is connecting to devices - i/o - so most time is spend on waiting (this is the reason we decided to make the connection init parallel).tring to connect to the same device from 2 different threads may cause problems.
I would suggest you don't create Threads at all but use the TaskScheduler and work with the Parallel Task Library:
http://msdn.microsoft.com/en-us/library/dd997402%28v=vs.110%29.aspx
The TaskScheduler himself is a wrapper for the ThreadPool, which handles the Threads. It even does stuf like WorkStealing, Task Inling etc.
At best you start here: http://msdn.microsoft.com/en-us/library/dd997402%28v=vs.110%29.aspx
Another approach is to start Tasks with a CancalletionToken, which enables you to cancel Tasks. See here: http://msdn.microsoft.com/en-us/library/dd537607%28v=vs.110%29.aspx
Edit: Okey, no TPL, Blocking Threads. This leaves basically only the Thread.Abort.
This is messy, but there is no perfect world, so think about the Form as Application A, and ClassB is Application B:
public partial class MainWindow : Window
{
Thread _threadA;
Thread _threadB;
Thread _threadC;
ClassB b1 = new ClassB();
ClassB b2 = new ClassB();
ClassB b3 = new ClassB();
public MainWindow()
{
InitializeComponent();
_threadA = new Thread(() => b1.DoSomeWork("A"));
_threadB = new Thread(() => b2.DoSomeWork("B"));
_threadC = new Thread(() => b3.DoSomeWork("C"));
}
private void btnStartWork_Click(object sender, RoutedEventArgs e)
{
_threadA.Start();
_threadB.Start();
_threadC.Start();
}
private void btnStopThreadA_Click(object sender, RoutedEventArgs e)
{
AbortThreadA();
}
private void btnStopThreadB_Click(object sender, RoutedEventArgs e)
{
AbortThreadB();
}
private void btnStopThreadC_Click(object sender, RoutedEventArgs e)
{
AbortThreadC();
}
private void AbortThreadA()
{
_threadA.Abort();
}
private void AbortThreadB()
{
_threadB.Abort();
}
private void AbortThreadC()
{
_threadC.Abort();
}
private void btnStopAll_Click(object sender, RoutedEventArgs e)
{
AbortThreadA();
AbortThreadB();
AbortThreadC();
}
}
class ClassB
{
public void DoSomeWork(string threadIdentifier)
{
try
{
string preWorkString = "Work work Okeydokey. Thread: " + threadIdentifier;
string postWorkString = "Job's Done. Thread: " + threadIdentifier;
while (true)
{
System.Diagnostics.Debug.WriteLine(preWorkString);
Thread.Sleep(5000);
System.Diagnostics.Debug.WriteLine(postWorkString);
}
}
catch (ThreadAbortException)
{
System.Diagnostics.Debug.WriteLine("Thread aborted. Thread: " + threadIdentifier);
Thread.ResetAbort();
}
}
}
ResetAbort is needed, otherwise the Error gets bubbled.
Is that a possible solution?
Do you own B-method (ie can you change it?)
I'm assuming B-method is not intrinsically cancellable, and you are just cancelling the background worker that calls it in module A?
B-method needs to be changed to either be cancellable, or re-entrant. By re-entrant I mean that it will allow multiple calls to itself, and will re-use any existing init sequence that is already in progress.

How to stop task(thread) and release in other task? [duplicate]

Hi guys I start threads with such code:
Thread[] thr;
private void button1_Click(object sender, EventArgs e)
{
decimal value = numericUpDown2.Value;
int i = 0;
threads_count = (int)(value);
thr = new Thread[threads_count];
for (; i < threads_count; i++)
{
thr[i] = new Thread(new ThreadStart(go));
thr[i].IsBackground = true;
thr[i].Start();
}
}
How to stop all them if my condition become true
A number of the answers say to abort the thread. Never abort a thread unless it is an emergency situation and you are shutting down the application.
The CLR guarantees that its internal data structures are not corrupted by a thread abort. This is the only (*) guarantee made by the CLR with respect to thread aborts. It specifically does not guarantee:
That the thread actually will abort. Threads can harden themselves against being terminated.
That any data structure that is not in the CLR itself will be uncorrupted. Thread aborts in the middle of crucial operations can leave BCL data structures or user data structures in arbitrarily inconsistent states. This can crash your process mysteriously later.
That locks will be released. Aborting threads can cause locks to be held forever, it can cause deadlocks, and so on.
In case I am not being clear: it is insanely dangerous to abort a thread and you should only do so when all the alternatives are worse.
So what if you want to start up a thread and then shut it down cleanly?
First, don't do that. Don't start a thread in the first place. Start a Task<T> with a cancellation token and when you want to shut it down, signal its cancellation token.
If you do have to start a thread, then start the thread such that there is some mechanism whereby the main thread and the working thread can cleanly and safely communicate "I want you to shut yourself down cleanly at this time".
If you don't know how to do that then stop writing multithreaded code until you learn how to do that.
(*) This is a small lie; the CLR also makes certain guarantees with respect to the interactions of thread aborts and special code regions such as constrained execution regions and finally blocks.
You can use a CancellationToken to signal when the operation should stop.
Create a CancellationTokenSource as an instance field of your type that you initialize in the button click handler.
In your background method periodically check the IsCancellationRequested property of the Token in the token source, or call ThrowIfCancellationRequested() if you want it to just throw an exception if it is canceled.
When you want to stop the threads call Cancel on the token source.
Brutal way (not recommended) - use Thread.Abort method to abort threads. This method raises ThreadAbortException on thread. Like this:
foreach(Thread thread in thr)
thread.Abort();
But better way is notifying thread about cancellation and letting it correctly finish its job. You can do it simply with .Net 4 tasks:
Task[] thr = new Task[threads_count];
var source = new CancellationTokenSource();
for (int i = 0; i < threads_count; i++)
{
thr[i] = Task.Factory.StartNew(go, source.Token);
}
// later, when condition is met
source.Cancel();
And here is how cancellation should look like:
private static void go(object obj)
{
CancellationToken token = (CancellationToken)obj;
while (true)
{
if (token.IsCancellationRequested)
return;
// do some work
}
}
If you want to know how to terminate the thread gracefully, I'd recommend you to take a look the following example on MSDN:
using System;
using System.Threading;
public class Worker
{
public void DoWork()
{
while (!_shouldStop)
{
Console.WriteLine("worker thread: working...");
}
Console.WriteLine("worker thread: terminating gracefully.");
}
public void RequestStop()
{
_shouldStop = true;
}
// Volatile is used as hint to the compiler that this data
// member will be accessed by multiple threads.
private volatile bool _shouldStop;
}
public class WorkerThreadExample
{
static void Main()
{
Worker workerObject = new Worker();
Thread workerThread = new Thread(workerObject.DoWork);
workerThread.Start();
Console.WriteLine("main thread: Starting worker thread...");
while (!workerThread.IsAlive); // Loop until worker thread activates
// Put the main thread to sleep for 1 millisecond to
// allow the worker thread to do some work:
Thread.Sleep(1);
workerObject.RequestStop();
// Use the Join method to block the current thread
// until the object's thread terminates.
workerThread.Join();
Console.WriteLine("main thread: Worker thread has terminated.");
}
}
This is Windows Form Code in which:
1) On Clicking start button, Main Thread creates another Thread
2) Again created Thread creates on more Thread.
3) On clicking Stop button, First the last Thread should terminate Then the Thread created by Main thread should Terminate.
namespace Thread_TerminateProblem
{
public partial class Form1 : Form
{
private static AutoResetEvent m_ResetEvent = null;
private static ManualResetEvent m_ResetEvent_Thread = new ManualResetEvent(false);
enum ServiceState { Start, Stop };
bool flag = false;
int x = 0;
ServiceState _state;
public Form1()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
flag = true;
_state = ServiceState.Start;
m_ResetEvent = new AutoResetEvent(true);
Thread t1 = new Thread(fun_Thread1);
t1.Start();
t1.Name = "Thread1";
}
private void btnStop_Click(object sender, EventArgs e)
{
_state = ServiceState.Stop;
m_ResetEvent.Set();
}
private void fun_Thread1()
{
while (true)
{
m_ResetEvent.WaitOne();
switch (_state)
{
case ServiceState.Start:
{
Thread t = new Thread(fun_Thread2);
t.Start();
t.Name = "Thread2";
break;
}
case ServiceState.Stop:
{
m_ResetEvent_Thread.Set();
flag = true;
break;
}
}
// When the child Thread terminates, Then only this thread should terminate
if (flag == true)
{
// Waiting for notification from child Thread
notifyParent.WaitOne();
Thread.Sleep(100);
break;
}
m_ResetEvent.Reset();
}
}
private static ManualResetEvent notifyParent = new ManualResetEvent(false);
private void fun_Thread2()
{
while (true)
{
if (m_ResetEvent_Thread.WaitOne(1, false))
{
notifyParent.Set();
break;
}
x++;
}
}
}
}
simplistic answer is to use the thread Abort() method however your code does not really make it clear what condition,
what loop tests vs a condition? why do you need to abort a thread? I am asking as there may be a better way to approach this

Close a form from a thread

I have a Thread that starts in my main form
private void changePasswordbutton_Click_1(object sender, EventArgs e)
{
waitForm.Show();
Thread thread = new Thread(ProcessInkPresenter);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
waitForm.Hide();
waitForm.Dispose();
}
I want to close the waitForm inside the ProcessInkPresenter method (which is running on a thread) instead of waiting for the thread to complete.
How do I do this?
Thanks
Method signatures
private void ProcessInkPresenter()
Defined in the class header
Wait waitForm;
Your original code doesn't make sense. It shows a form, then starts a thread, then waits for that thread to complete. If you want the form to be run on it's own UI thread, have ProcessInkPresenter run on the same UI thread (which it should if it interacts with the UI) and have the form closed and be disposed of when ProcessInkPresenter completes, try this:
private void changePasswordbutton_Click_1(object sender, EventArgs e)
{
Thread thread = new Thread(state => {
using (var waitForm = new WaitForm()) {
waitForm.Activated += (s, e) => {
ProcessInkPresenter();
waitForm.Hide();
}
Application.Run(waitForm);
}
}
);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
If the worker thread does not have to interact with the GUI, then what you want is something like the following. Note that I make use of Invoke to make sure that the interaction with the UI is done on the UI thread. There is no need to check InvokeRequired here, since I already know for sure that I am on a background thread.
If you want to keep the same waitForm instance:
private void changePasswordbutton_Click_1(object sender, EventArgs e)
{
Thread thread = new Thread(state => {
try {
ProcessInkPresenter();
// If ProcessInkPresenter fails, this line will never execute
waitForm.Invoke(new Action(()=>waitForm.Hide()));
}
catch (Exception ex) {
// You probably want to do something with ex here,
// rather than just swallowing it.
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
waitForm.Show();
}
NOTE: It doesn't make sense to dispose your WaitForm if you have a single instance of it (your Wait instance). Either construct an instance each time you use it, or never dispose it and use .Hide() instead.

Cancelling Background Tasks

When my C# application closes it sometimes gets caught in the cleanup routine. Specifically, a background worker is not closing. This is basically how I am attempting to close it:
private void App_FormClosing(object sender, FormClosingEventArgs e)
{
backgroundWorker1.CancelAsync();
while (backgroundWorker1.IsBusy) ; // Gets stuck here.
}
Is there a different way that I should be doing this? I am using Microsoft Visual C# 2008 Express Edition. Thanks.
ADDITIONAL INFORMATION:
The background worker does not appear to be exiting. This is what I have:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (!backgroundWorker1.CancellationPending)
{
// Do something.
}
}
I've also modified the cleanup code:
private void App_FormClosing(object sender, FormClosingEventArgs e)
{
while (backgroundWorker1.IsBusy)
{
backgroundWorker1.CancelAsync();
System.Threading.Thread.Sleep(1000);
}
}
Is there something else that I should be doing?
Some pretty good suggestions, but I don't believe they address the underlying issue: canceling a background task.
Unfortunately, when using BackgroundWorker, termination of your task depends on the task itself. The only way your while loop will terminate, is if your background task checks its Cancel property and returns or breaks from its current process.
Example Base
For example, consider
private readonly BackgroundWorker worker = new BackgroundWorker ();
public void SomeFormEventForStartingBackgroundTask ()
{
worker.DoWork += BackgroundTask_HotelCalifornia;
worker.WorkerSupportsCancellation = true;
worker.RunWorkerAsync ();
}
// semantically, you want to perform this task for lifetime of
// application, you may even expect that calling CancelAsync
// will out and out abort this method - that is incorrect.
// CancelAsync will only set DoWorkEventArgs.Cancel property
// to true
private void BackgroundTask_HotelCalifornia (object sender, DoWorkEventArgs e)
{
for ( ; ;)
{
// because we never inspect e.Cancel, we can never leave!
}
}
private void App_FormClosing(object sender, FormClosingEventArgs e)
{
// [politely] request termination
worker.CancelAsync();
// [politely] wait until background task terminates
while (worker.IsBusy);
}
This is what is happening by default. Now, maybe your task isn't an infinite loop, perhaps it is just a long-running task. Either way, your main thread will block [actually it is spinning, but whatevs] until the task completes, or doesn't as the case may be.
If you have personally written and can modify the task, then you have a few options.
Example Improvement
For instance, this is a better implementation of the above example
private readonly BackgroundWorker worker = new BackgroundWorker ();
// this is used to signal our main Gui thread that background
// task has completed
private readonly AutoResetEvent isWorkerStopped =
new AutoResentEvent (false);
public void SomeFormEventForStartingBackgroundTask ()
{
worker.DoWork += BackgroundTask_HotelCalifornia;
worker.RunWorkerCompleted += BackgroundTask_Completed;
worker.WorkerSupportsCancellation = true;
worker.RunWorkerAsync ();
}
private void BackgroundTask_HotelCalifornia (object sender, DoWorkEventArgs e)
{
// execute until canceled
for ( ; !e.Cancel;)
{
// keep in mind, this task will *block* main
// thread until cancel flag is checked again,
// so if you are, say crunching SETI numbers
// here for instance, you could still be blocking
// a long time. but long time is better than
// forever ;)
}
}
private void BackgroundTask_Completed (
object sender,
RunWorkerCompletedEventArgs e)
{
// ok, our task has stopped, set signal to 'signaled' state
// we are complete!
isStopped.Set ();
}
private void App_FormClosing(object sender, FormClosingEventArgs e)
{
// [politely] request termination
worker.CancelAsync();
// [politely] wait until background task terminates
isStopped.WaitOne ();
}
While this is better, it's not as good as it could be. If you can be [reasonably] assured your background task will end, this may be "good enough".
However, what we [typically] want, is something like this
private void App_FormClosing(object sender, FormClosingEventArgs e)
{
// [politely] request termination
worker.CancelAsync();
// [politely] wait until background task terminates
TimeSpan gracePeriod = TimeSpan.FromMilliseconds(100);
bool isStoppedGracefully = isStopped.WaitOne (gracePeriod);
if (!isStoppedGracefully)
{
// KILL! KILL! KILL!
}
}
Alas, we cannot. BackgroundWorker does not expose any means of forceful termination. This is because it is an abstraction built on top of some hidden thread management system, one which could potentially destabalize other parts of your application if it were forcefully terminated.
The only means [that I have seen at least] to implement the above is to manage your own threading.
Example Ideal
So, for instance
private Thread worker = null;
// this time, 'Thread' provides all synchronization
// constructs required for main thread to synchronize
// with background task. however, in the interest of
// giving background task a chance to terminate gracefully
// we supply it with this cancel signal
private readonly AutoResetEvent isCanceled = new AutoResentEvent (false);
public void SomeFormEventForStartingBackgroundTask ()
{
worker = new Thread (BackgroundTask_HotelCalifornia);
worker.IsBackground = true;
worker.Name = "Some Background Task"; // always handy to name things!
worker.Start ();
}
private void BackgroundTask_HotelCalifornia ()
{
// inspect cancel signal, no wait period
//
// NOTE: so cheating here a bit, this is an instance variable
// but could as easily be supplied via parameterized thread
// start delegate
for ( ; !isCanceled.WaitOne (0);)
{
}
}
private void App_FormClosing(object sender, FormClosingEventArgs e)
{
// [politely] request termination
isCanceled.Set ();
// [politely] wait until background task terminates
TimeSpan gracePeriod = TimeSpan.FromMilliseconds(100);
bool isStoppedGracefully = worker.Join (gracePeriod);
if (!isStoppedGracefully)
{
// wipe them out, all of them.
worker.Abort ();
}
}
And that there, is a decent introduction on thread management.
Which is best suited for you? Depends on your application. It is probably best not to rock the boat, and modify your current implementation to ensure that
your background task inspects and respects the Cancel property
your main thread waits for completion, as opposed to polling
It is very important to compare and evaluate the pros and cons of each approach.
If you must control and guarantee termination of someone else's tasks, then writing a thread management system that incorporates the above may be the way to go. However you would lose out on out-of-box features like thread pooling, progress reporting, cross-thread data marshalling [worker does that, no?], and a bunch of other stuff. Not to mention, "rolling your own" is often error prone.
Anyway, hope this helps :)
Kevin Gale is correct in stating that your BackgroundWorker's DoWork handler needs to poll for CancellationPending and return if a cancellation is requested.
That being said, if this is happening when your application is shutting down, you can just ignore it safely, as well. BackgroundWorker uses a ThreadPool thread, which is, by definition, a background thread. Leaving this running will not prevent your application from terminating, and the thread will automatically be torn down when your application shuts down.
In the background worker thread you need to check the BackgroundWorker.CancellationPending flag and exit if it is true.
The CancelAsync() just sets this flag.
Or to put it another way. CancelAsync() doesn't actually cancel anything. It won't abort the thread or cause it to exit. If the worker thread is in a loop and checks the CancellationPending flag periodically it can catch the cancel request and exit.
MSDN has an example here although it doesn't use a loop in the worker routine.
This code is guaranteed to deadlock when the BGW is still running. BGW cannot complete until its RunWorkerCompleted event finished running. RunWorkerCompleted cannot run until the UI thread goes idle and runs the message loop. But the UI thread isn't idle, it is stuck in the while loop.
If you want the BGW thread to complete cleanly, you have to keep your form alive. Check this thread to see how to do that.
Try:
if (this.backgroundWorker1.IsBusy) this.backgroundWorker1.CancelAsync();

Categories