views:

2179

answers:

5

Hi All,

I am writing a windows application that runs a sequence of digital IO actions repeatedly.

This sequence of actions starts when the user click a "START" button, and it is done by a background worker in backgroundWorker1_DoWork().

However, there are occasions when I get the "This backgroundworker is currently busy......." error message.

I am thinking of implementing the following in the code, by using a while loop to "kill" the background worker before starting another sequence of action:

if (backgroundWorker1.IsBusy == true)
{

    backgroundWorker1.CancelAsync();
    while (backgroundWorker1.IsBusy == true)
    {
        backgroundWorker1.CancelAsync();
    }

    backgroundWorker1.Dispose();

}

backgroundWorker1.RunWorkerAsync();

I think my main concern is, will the backgroundWorker1 be "killed" eventually? If it will, will it take a long time to complete it?

Will this coding get me into an infinite loop?

+11  A: 

I'm of the opinion that threads should be responsible for their own resource as much as practicable, including their own lifetime.

It's always a bad idea to kill threads from outside their scope. Applications that are engineered to pass a message to the thread to shut itself down tend to have far less problems related to multi-threaded behavior.

A thread should monitor for said message, which can be as simple as a boolean set by another thread and read by that monitoring thread, in a timely fashion and shut itself down cleanly as soon as it can.

That means if it should look for the message:

  • in it's main loop, if any.
  • periodically in any long-running loops.

The thread shutting it down with the message should wait (but don't halt the GUI, of course).

paxdiablo
A: 

But what if I need to kill it (even though I agree that it's a bad idea)? In my case I have a NT-service wich starts a backgroundworker. In this backgroundworker I use MS Word to convert .docx to .pdf. Something like this:

DoWork()
{
    Word w = new App();

    if(CancellationPending)
       //clean exit 

    //This line is potentially a blocking call :(
    Doc d = w.Open();

    e.Result = true;
}

MS Word might pop-up a user dialog if the .docx is corrupt. My solution today is to kill the winword.exe process after a given amount of time.. this ends the w.Open() call... But what if I really want to kill the backgroundworker, is it even possible? Or du I need to use the Thread class?

Thomas
A: 

hey i was having the same problem im not sure if this will help but im guessing your background worker has a loop within or it would exit

what u need to do is put ur loop within

put inside your background worker

do until backgroundworker1.CancellationPending = true ,,,,,,,,,,(Put you code in here),,,,,,,,,, loop


and to get kill this backgroundworker you can put in your button


BackgroundWorker1.CancelAsync()

i hope this helps

echrom
A: 

You can use something like this (for more information about aborting managed threads and about ThreadAbortException see "Plumbing the Depths of the ThreadAbortException Using Rotor" by Chris Sells):

public class AbortableBackgroundWorker : BackgroundWorker
{

    private Thread workerThread;

    protected override void OnDoWork(DoWorkEventArgs e)
    {
        workerThread = Thread.CurrentThread;
        try
        {
            base.OnDoWork(e);
        }
        catch (ThreadAbortException)
        {
            e.Cancel = true; //We must set Cancel property to true!
            Thread.ResetAbort(); //Prevents ThreadAbortException propagation
        }
    }


    public void Abort()
    {
        if (workerThread != null)
        {
            workerThread.Abort();
            workerThread = null;
        }
    }
}

Usage:

backgroundWorker1 = new AbortableBackgroundWorker();
//...
backgroundWorker1.RunWorkerAsync();

if (backgroundWorker1.IsBusy == true)
{
    backgroundWorker1.Abort();
    backgroundWorker1.Dispose();
}
Sergey Teplyakov
A: 

I put one together that (i think) does the job. Please let me know if im waaaay off. Here is a simple exaple of how it works.

var backgroundWorker = new BackgroundWorker(){WorkerSupportsCancellation = true};

backgroundWorker.DoWork += (sender, args) =>
         {                 
                 var thisWorker = sender as BackgroundWorker;
                 var _child = new Thread(() =>
                                               {
                                                   //..Do Some Code

                                               });
                 _child .Start();
                 while (_child.IsAlive)
                 {
                     if (thisWorker.CancellationPending)
                     {
                         _child.Abort();
                         args.Cancel = true;
                     }
                     Thread.SpinWait(1);
                 }                 
         };

 backgroundWorker.RunWorkerAsync(parameter);
 //..Do Something...
backgroundWorker.CancelAsync();

Since the background worker is part of the thread pool, we dont want to abort it. But we can run a thread internally which we can allow an abort to occur on. The backgroundWorker then basically runs until either the child thread is complete or we signal to it to kill the process. The background worker thread can then go back into the read pool. Typically I will wrap this up in a helper class and pass through the delegate method that I want the background thread to run passed in as the parameter and run that in the child thread.

Please someone let me know if im banging my head against a wall but it seems to work fine.. But thats the problem with threads isnt it.. the varying results you can get when you run it at different times.

Rob
-1: for `.Abort()` in a new design suggestion.
280Z28
Very, very dangerous to `Abort` a thread externally. Please read: http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation. Basically, this is very very wrong in **three** ways: (1) creating an unnecessary extra thread, (2) busy-waiting on it, and (3) aborting it at a potentially critical moment without allowing proper cleanup.
Aaronaught
The response above also uses a child-thread + abort type of solution. Is there a better way to deal with this?
Rob