[英]How do I abort multiple threads?
在此代码中,当单击button1
两次时,它会创建2个单独的线程。 只需单击一下,它就会在堆上创建一个新线程,而字段t1
指向堆上的新线程。 当我单击button2
,它将中止最后一个线程( t1
指的是)。
我如何中止其他线程?
Thread t1;
ThreadStart ts1;
private void button1_Click(object sender, EventArgs e)
{
ts1 = new ThreadStart(myfunc);
t1 = new Thread(ts1);
t1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
t1.Abort();
}
好吧,OO的答案是将一个线程列表作为一个字段。
private readonly List<Thread> threads = new List<Thread>();
然后将新构造的线程添加到第一个处理程序的列表中。
var thread = new Thread(myfunc);
thread.Start();
threads.Add(thread);
然后你可以迭代第二个处理程序中的每个线程,依次中止每个线程。
foreach(var thread in threads)
thread.Abort();
但我认为这里最重要的一点是, 几乎没有理由调用Thread.Abort
。
从MSDN页面 :
当一个线程自身调用Abort时,效果类似于抛出异常; ThreadAbortException立即发生,结果是可预测的。 但是,如果一个线程在另一个线程上调用Abort,则中止将中断正在运行的任何代码。 静态构造函数也有可能被中止。 在极少数情况下,这可能会阻止在该应用程序域中创建该类的实例。 在.NET Framework 1.0和1.1版本中,当finally块正在运行时,线程可能会中止,在这种情况下,finally块将被中止。
如果正在中止的线程位于受保护的代码区域(例如catch块,finally块或约束执行区域),则调用Abort的线程可能会阻塞。 如果调用Abort的线程持有中止线程所需的锁,则可能发生死锁。
使用某种形式的信令会更好,例如设置每个线程将以perioidic间隔轮询的ManualResetEvent
。 或者,您可以使用对任务取消有一定支持的BackgroundWorker
类(对其调用CancelAsync
,并让工作线程定期测试CancellationPending
)。 如果您使用的是.NET 4.0,则还可以使用TPL 。
我建议你看看内置的同步原语,如ManualResetEvent和WaitHandle。 通过尝试使用Thread.Join加入线程,您可以询问线程是否正在运行。 如果线程没有响应,则只应作为最后的手段中止线程。
以下是代码的修改示例,其中显示了如何在正确停止线程之前阻止线程重新启动。
public partial class MainForm : Form
{
private Thread t1;
private ThreadStart ts1;
private ManualResetEvent t1resetEvent;
public MainForm()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Got a thread?
if (t1 != null) {
if (!t1.Join(0)) {
// The thread seems to be running.
// You have to stop the thread first.
return;
}
}
t1resetEvent = new ManualResetEvent(false);
ts1 = new ThreadStart(MyFunc);
t1 = new Thread(ts1);
t1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
// Got a thread?
if (t1 != null)
{
// Set the reset event so the thread
// knows it's time to stop.
t1resetEvent.Set();
// Give the thread four seconds to stop.
if (!t1.Join(4000)) {
// It did not stop, so abort it.
t1.Abort();
}
}
}
private void MyFunc()
{
// Long running operation...
while (true)
{
// Do someone want us to exit?
if (t1resetEvent.WaitOne(0)) {
return;
}
}
}
}
其他人给出了答案的长版本,但显而易见的简单解决方案是简单地跳过重新创建线程对象:
public partial class Form1 : Form
{
Thread thread1;
ThreadStart threadStart1;
public Form1()
{
InitializeComponent();
threadStart1 = new ThreadStart(threadTarget);
thread1 = new Thread(threadStart1);
thread1.Name = "Button1 thread";
}
private void button1_Click(object sender, EventArgs e)
{
thread1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
thread1.Abort();
}
private void threadTarget()
{
Console.WriteLine(Thread.CurrentThread.Name);
for (int i = 0; i < 100; i++)
{
Console.WriteLine(i);
Thread.Sleep(500);
}
}
}
但是,我会考虑使用这些指南阅读.NET中的线程( 我推荐Joseph Albahari关于流产的指南 - 简而言之是C#的作者 )而不是使用这种方法,特别是如果你正在执行IO或数据库可以使对象处于意外状态的操作。
另外,请记住,在线程上调用Abort是邪恶的。 你应该用布尔条件或类似的东西来停止线程。
检查一下:
http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.