如何停止线程以获取耗时的函数
本文关键字:函数 获取 何停止 线程 | 更新日期: 2023-09-27 18:36:33
我正在尝试做一个Windows应用程序,我有一个需要几分钟才能完成任务的函数。我有一个开始按钮和我想添加一个停止按钮,以便在我想停止函数时停止函数的处理。
我正在尝试使用下面的代码,但我不确定如何在 btnStop 中中止 Thread1,因为 Thread1 被标记为"不存在"在当前背景下"。
请您建议我/指出我如何做到这一点的好方法。提前谢谢。
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");
}
}
}
更新:嗨,KCdod,感谢您的帮助,当我只将线程声明为全局变量时,我得到"类型为'System.NullReferenceException'的未处理异常"发生在 SampleStartStop.exe"。
嗨,阿列克谢,感谢您的更正。感谢 zerkms 和 Alexei 分享有关取消令牌的信息。按照您共享的链接中的示例进行操作我能够编写下面的代码。它似乎有效,但如果它需要一些更改或是否正常,我希望得到专家的认可。
关于当前代码的唯一疑问是,如果按下停止按钮,它会停止处理,但是如果我再次单击开始按钮,什么也没发生,我需要关闭并再次打开应用程序才能再次开始按钮,这正常吗?
另一个疑问在"听众"中的部分。在MSDN示例中,他们输入"//如有必要执行清理",那么,什么样的清理他们在谈论?
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");
}
}
}
更新:感谢阿列克谢的更正,我已经根据您的建议修改了代码,这次效果很好。代码如下。我只有一个问题,因为在我的真实代码中,该函数需要一个字符串参数才能工作,我不知道如何在"WaitCallback(SlowFunction)"部分中调用它以及如何在代码中定义函数,因为这里定义是这样的"公共无效慢函数(对象 obj){...}",在我的真实函数中就像这个"公共无效慢函数(字符串 str)"。我想我需要在这个问题上提出一个新问题。
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");
}
}
}
}
没有很好的方法来终止不合作的线程。事实上,Thread.Abort
会这样做,但代价是可能会留下未释放的对象和废弃的同步原语,从而可能破坏程序的稳定性。
修复您的直接问题 - 将Thread1
移动到类级别成员而不是局部变量。您需要检查它是否已设置/清除:
public partial class Form1 : Form {
...
Thread thread1 = null;
private void btnStart_Click(object sender, EventArgs e)
{
if (thread1 != null)
{
thread1.Abort();
}
thread1 = new Thread(SlowFunction);
Thread1.Start();
}
private void btnStop_Click(object sender, EventArgs e)
{
if (thread1 != null)
{
thread1.Abort();
thread1 = null;
MessageBox.Show("Processing canceled");
}
}
如果您可以使"慢速功能"在终止中合作 - 即通过定期检查某个值,那就更好了。检查取消令牌以了解 .Net 执行此操作的方式。
您可以将线程Thread Thread1;
声明为全局变量。在当前代码中,Thread1
范围限制为btnStart_Click()
事件函数。
namespace SampleStartStop
{
public partial class Form1 : Form
{
Thread Thread1=null;
public Form1()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
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");
}
}
}
附加 - 线程中止不好,但您可以使用它。