Reputation: 71
I have a problem implementing code i got from stackowerflow its about killing a backgroundworker process.
My code is as follows:
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;
using GluthGUI.Classes.XMLprofile;
using System.Xml.Linq;
using System.ComponentModel;
namespace Solution
{
partial class SolGUI : Form
{
private void startButton_Click(object sender, EventArgs e)
{
backgroundWorker1 = new AbortableBackgroundWorker();
if (startButton.Text == "Start")
{
XMLParsing();
DisableTextFields();
backgroundWorker1.RunWorkerAsync();
startButton.Text = "Stop";
}
else if (startButton.Text == "Stop")
{
if (backgroundWorker1.IsBusy == true)
{
backgroundWorker1.Abort(); //error Abort() is not declared?!?!
backgroundWorker1.Dispose();
}
startButton.Text = "Start";
DisableTextFields();
}
}
}
This is a partial class which would terminate backgroundworker:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Threading;
namespace Solution
{
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;
}
}
}
}
My problem is that Abort() method from partial class is not visible in other classes with same namespace.
Upvotes: 0
Views: 1020
Reputation: 48435
The problem is that you are defining the backgroundWorker1
with the type of BackgroundWorker
, so you do not have access to the custom methods defined in your AbortableBackgroundWorker
class.
Either add a AbortableBackgroundWorker
directly to your designer, or declare the AbortableBackgroundWorker
manually within your form:
partial class SolGUI : Form
{
AbortableBackgroundWorker backgroundWorker1 = new AbortableBackgroundWorker();
You also need to make sure you remove this line of code from your button click event:
backgroundWorker1 = new AbortableBackgroundWorker();
because that is causing a new instance to be set each time you click and you will never get access to the original instance in order to abort it. You should also not dispose the object at any point as you will want to reuse it when you start the process again, so remove:
backgroundWorker1.Dispose();
You will also need to hook up any events you are using, such as DoWork
. You should do this in your forms constructor like so:
backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
I am not going to go in to any detail about whether or not you should be aborting threads, others have commented and that is your choice if you want to follow their advice and do some research. I have simply answered the question at hand. Personally though, I would use the built-in cancellation methods.
Upvotes: 3
Reputation: 18023
Unless the subscribed method of the DoWork
event is a plugin or a 3rd party code that you cannot maintain, it is usually a very bad idea to abort a thread directly.
When you click the Stop button you must pass the cancellation request to your worker object; otherwise, it will never be notified. The BackgroundWorker
has a CancelAsync
method that 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 canceled.
So what you need:
MyWorkerObject 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 MyWorkerObject();
// 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 MyWorkerObject
{
// 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 && ...)
{
// ...
}
}
}
Upvotes: 2
Reputation: 542
backgroundWorker1 = new AbortableBackgroundWorker();
this line is the problem, each time you click the button you create a new instance of background worker. you should define if outside of the method it should be ok
Upvotes: -1
Reputation: 1213
Variable backgroundWorker1
has been defined as a BackgroundWorker
while it should be defined as a AbortableBackgroundWorker
in the other part of your partial class.
Perhaps you could find it as SolGUI.Desinger.cs in the solution explorer.
Upvotes: 1