问题
I have a windows form which utilizes a backgroundworker. The backgroundworker instantiates an object and then executes a method in that object. My problem is that when I use backgroundworker.CancelAsync the method running on the remote object does not stop. In the example below, the dowork method continues to execute after button cancel is clicked. FYI, dowork is looping thru a spreadsheet and doing some data manipulation based on the rows in the spreadsheet.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
myObject newObject = new myObject();
newObject.dowork();
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
backgroundWorker1.ReportProgress(0);
return;
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy) backgroundWorker1.CancelAsync();
}
Thoughts?
Thanks
回答1:
In btnCancel_Click
you must pass the cancellation request to your worker object; otherwise, it will never be notified. The BackgroundWorker.CancelAsync()
does not do anything just simply sets the BackgroundWorker.CancellationPending
property, notifying the consumer of the BackgroundWorker (the UI, not the executed task) that your task has been cancelled.
So what you need:
MyObject myObject;
// This method is executed on the worker thread. Do not access your controls
// in the main thread from here directly.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
myObject = new MyObject();
// The following line is a blocking operation in this thread.
// The user acts in the UI thread, not here, so you cannot do here
// anything but wait.
myObject.DoWork();
// Now DoWork is finished. Next line is needed only to notify
// the caller of the event whether a cancel has happened.
if (backgroundWorker1.CancellationPending)
e.Cancel = true;
myObject = null;
}
private void btnCancel_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy)
{
backgroundWorker1.CancelAsync();
// You must notify your worker object as well.
// Note: Now you access the worker object from the main thread!
// Note2: It would be possible to pass the worker to your object
// and poll the backgroundWorker1.CancellationPending from there,
// but that would be a nasty pattern. BL objects should not
// aware of the UI components.
myObject.CancelWork();
}
}
And how should you implement the notification:
public class MyObject
{
// normally you should use locks to access fields from different threads
// but if you just set a bool from one thread and read it from another,
// then it is enough to use a volatile field.
private volatile bool isCancelRequested;
// this will be called from the main thread
public void CancelWork()
{
isCancelRequested = true;
}
// This method is called from the worker thread.
public void DoWork()
{
// Make sure you poll the isCancelRequested field often enough to
// react to the cancellation as soon as possible.
while (!isCancelRequested && ...)
{
// ...
}
}
}
来源:https://stackoverflow.com/questions/31483760/stopping-thread-started-by-backgroundworker