Cancelling a BackgroundWorker thread

G

Guest

I have a long database search operation that I am running in a separate
thread using a BackgroundWorker component. I need to give the user the
ability to cancel the operation. However, the BackgroundWorker doesn't seem
to have enough functionalality to solve my problem.

I start the thread with:

backgroundWorker.RunWorkerAsync(SQLQueryString);

The event handler looks like this:

void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Define a dataAdapter using SQLQueryString, OleDBConnection etc.
OleDataAdapter da = ... etc
......
// Fill the datatable
da.Fill(dataTable);
}

Most of the time is spent in the Fill operation. The documented approach for
canceling a long operation is to:

backgroundWorker.CancelAsync();

and in the DoWork handler, periodically check for a cancel with:

if (backgroundWorker.CancellationPending) return; // triggers WorkCompleted

My problem is that the dataAdapter Fill operation can't be interrupted. So,
I would have to modify the database query and Fill the data table
incrementally like:

for (i = 0; i < 10; ++i)
{
// run modified query, getting 10% of results
.......
// Fill 10% of the datatable
da.Fill(dataTable);

// Report progress (Optional)
backgroundWorker.ReportProgress(i * 10);

// Check for cancel
if (backgroundWorker.CancellationPending) return; // Triggers WorkComplete
}

Unfortunately, this comes with a performance hit. So, instead of the above
approach, I do the following:

1. Get the backgroundWorker thread object (= workerThread).
2. workerThread.Abort()
3. backGroundWorker.Dispose()
4. For a new query, create a new BackgroundWorker.

Note that if I skip 3 and try to launch another query using the original
backgroundWorker, I get an exception saying the backgroundGround worker is
busy, even though the thread was aborted.

This seems like a bit of a hack. Is there a better solution?

Any ideas appreciated.
 
A

Andy

Well, there's not much you can do if you can't cancel the underlying
operation.

Andy
 
T

TP

Hi Bob,

Run the fill on a separate backgroundWorker. Have the first
backgroundWorker loop as long as the second
backgroundworker's IsBusy is true. In the loop, call a
thread.sleep(1000), check the CancellationPending property,
and, if true, call CancelAsync on the second backgroundWorker,
followed by a Cancel on the OleDbCommand.

This will cause the fill running on the second backgroundWorker
to raise an exception, so you will need to handle that.

-TP
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top