6

I have UI which displaying status of long-running operations (downloading some text files from ftp) . For my purposes I use backgroundworker and I can't cancel operation.

void worker_DoWork( object sender, DoWorkEventArgs e )
    {

        try
        {
            int rowIndex = (int)e.Argument;

            //begin UI update
            StartWaitingBar(rowIndex);
            //get provider id cell
            GridViewDataRowInfo row = _proivderGridView.Rows[rowIndex];
            GridViewCellInfo provIdCell = row.Cells[ "ProviderId" ];

            var providerData = GetProviderData(Convert.ToInt32( provIdCell.Value));
            var provider =  ProviderFactory.CreateProvider(providerData);
            provider.Synchronize();
            e.Result = rowIndex;

        }
        catch (Exception exception)
        {
           return;
        }
    }

And code for worker creation:

           BackgroundWorker worker = new BackgroundWorker();
           worker.DoWork += worker_DoWork;
           worker.RunWorkerCompleted += worker_RunWorkerCompleted;
           worker.WorkerSupportsCancellation = true;
           worker.RunWorkerAsync(args.RowIndex);
          _syncWorkers.Add(providerId,worker);
           ...
            var worker = _syncWorkers[providerId];

            if(worker.IsBusy)
             {
                 worker.CancelAsync();
             }
            else
            {
                worker.RunWorkerAsync(args.RowIndex);
            }   

Solution provided here seems not working for me beacuse it works for recurring operations (for which background worker is created, I suppose). Do I have to use threads(abort and join) for my purposes because I should provide possibilities for user to cancel long-running operation?

Need your advice.

Thanks in advance.

Community
  • 1
  • 1
Sharov
  • 458
  • 8
  • 38

2 Answers2

7

You cannot use Backgroundworker.CancelAsync() to cancel a long running I/O action. Like rifnl answered, the DoWork has to check worker.CancellationPending and set e.Cancel.

But you shouldn't use Thread.Abort() either. It could destabilize your process.

The solution you need has to come from provider.Synchronize(); somehow.

PS: and catch { return; } is horrible. Remove the entire try/catch and let the Bgw handle exceptions.

H H
  • 263,252
  • 30
  • 330
  • 514
  • Alternatively, if its possible to give the Synchronize a TimeOut value, you could put the synchronize in a while(!e.CancellationPending) privider.Synchronize(TimeOut); //if possible loop, while continuing the function you currently have. – greggorob64 Jul 15 '10 at 13:28
2

You've got to check e.Cancel within your DoWork method, which is missing from your code-snippet, but you've got to change your download method to an async call too, you're calling the method and wait for the answer within the dowork. Which is possible, but it won't check for the cancel flag in mean time.

Check the solution you posted (line 3):

void worker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    while(!e.Cancel) 
    { 
        // do something 
    } 

    _resetEvent.Set(); // signal that worker is done 
} 
riffnl
  • 3,248
  • 1
  • 19
  • 32
  • Thank you for reply! I understand your point, but do I have to use backgraound worker at all? I can use async operation (as I did it initially) and use AutoResetEvent to achieve cancelling... – Sharov Jul 15 '10 at 12:42
  • As riffnl stated, `BackgroundWorker` does support cancellation. You don't have to use `BackgroundWorker`, but I recommend moving *up* in abstraction to `Task`, rather than *down* in abstraction to asynchronous delegates. – Stephen Cleary Jul 15 '10 at 12:53
  • @Stephen, does .net 3.5 support Tasks? – Sharov Jul 15 '10 at 13:09
  • 1
    @Sharov: Bgw, Task and Async all have the same imitations. None of those can interrupt `Synchronize()` safely. – H H Jul 15 '10 at 13:21
  • @Sharov: not officially. Unofficial support exists as part of the [Rx library](http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx). – Stephen Cleary Jul 15 '10 at 13:27
  • @Sharov: what Henk means is that any cancellation scheme should be *cooperative*. So, `Synchronize` needs to check for cancellation somehow (periodic polling or listening to an event) and voluntarily exit when cancellation is requested. – Stephen Cleary Jul 15 '10 at 13:29