I'm trying to do a windows app and I have a function that takes several minutes to complete the task. I have a start button and I'd like to add a stop button in order to stop the processing of the function whenever I want to stop it.
I'm trying with the code below, but I'm not sure how to abort the Thread1 inside btnStop since Thread1 is marked as "does not exists in current context".
May you please suggest me/point me in rigth direction in how would be a good way to do this. Thanks in advance.
namespace SampleStartStop
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
Thread Thread1 = new Thread(SlowFunction);
Thread1.Start();
}
private void btnStop_Click(object sender, EventArgs e)
{
Thread1.Abort();
MessageBox.Show("Processing canceled");
}
public void SlowFunction()
{
var end = DateTime.Now + TimeSpan.FromSeconds(10);
while (DateTime.Now < end)
{ }
MessageBox.Show("Process finished");
}
}
}
Update: Hi KCdod, thanks for your help, When I only declare thread as global variable I get "An unhandled exception of type 'System.NullReferenceException' occurred in SampleStartStop.exe".
Hi Alexei, thanks for the correction. Thanks zerkms and Alexei for share about cancellation tokens. Following the example in link you shared I was able to write the code below. It seems to work but I'd like the approbal of you experts if it needs some change or if it is fine.
The only doubt regarding the current code is, if Stop button is pressed it stops the processing fine, but if I click start button again, nothing happens and I need to close and open again the App in order to get working again start button, is this normal?
The other doubt is in the part inside "The listener". In MSDN example they put "// Perform cleanup if necessary.", so, what kind of clean up they are talking about?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// Create the token source.
CancellationTokenSource cts = new CancellationTokenSource();
private void btnStart_Click(object sender, EventArgs e)
{
// Pass the token to the cancelable operation.
ThreadPool.QueueUserWorkItem(new WaitCallback(SlowFunction), cts.Token);
}
private void btnStop_Click(object sender, EventArgs e)
{
// Request cancellation.
cts.Cancel();
// Cancellation should have happened, so call Dispose.
cts.Dispose();
MessageBox.Show("Processing canceled");
}
public void SlowFunction(object obj)
{
CancellationToken token = (CancellationToken)obj;
var end = DateTime.Now + TimeSpan.FromSeconds(10);
while (DateTime.Now < end)
{
// Thread 2: The listener
if (token.IsCancellationRequested)
{
// Perform cleanup if necessary.
//...
// Terminate the operation.
break;
}
}
if (!token.IsCancellationRequested)
{
MessageBox.Show("Processing finished");
}
}
}
Update: Thanks Alexei for your correction, I've modified the code with your suggestions and this time works nice. the code is as below. I only have an issue since in my real code, the Function needs a string argument to work and I don't know how to call it inside the part "WaitCallback(SlowFunction)" and how to define the function in the code, since here is defined like this "public void SlowFunction(object obj) {...}" and in my real function is like this "public void SlowFunction(string str)". I think that I'd need to ask in a new question this issue.
namespace SampleStartStop
{
public partial class Form1 : Form
{
// Create the token source.
CancellationTokenSource cts = new CancellationTokenSource();
public Form1()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
if (cts != null)
{
cts.Cancel();
}
// Pass the token to the cancelable operation.
cts = new CancellationTokenSource();
ThreadPool.QueueUserWorkItem(new WaitCallback(SlowFunction), cts.Token);
}
private void btnStop_Click(object sender, EventArgs e)
{
if (cts != null)
{
cts.Cancel();
cts = null;
MessageBox.Show("Processing canceled");
}
}
public void SlowFunction(object obj)
{
CancellationToken token = (CancellationToken)obj;
var end = DateTime.Now + TimeSpan.FromSeconds(5);
while (DateTime.Now < end)
{
if (token.IsCancellationRequested)
{
break;
}
}
if (!token.IsCancellationRequested)
{
MessageBox.Show("Processing finished");
}
}
}
}