在此代码中,当单击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();
}
答案 0 :(得分:7)
嗯,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 page:
当一个线程调用Abort时, 效果类似于抛出一个 例外; ThreadAbortException 立即发生,结果是 可预测的。但是,如果一个线程 在另一个线程上调用Abort ,. abort 中断任何代码 跑步。还有一个机会 静态构造函数可以中止。 在极少数情况下,这可能阻止 该类的实例 在该应用程序域中创建。 .NET Framework版本1.0和 1.1,有一个机会线程可以在最后一个块时中止 跑步,在这种情况下终于 阻止中止。
调用Abort的线程可能 阻止正在进行的线程 流产是在受保护的地区 代码,例如catch块,最后 阻止或约束执行 区域。如果是调用Abort的线程 持有一个被中止线程的锁 需要,可能发生死锁。
使用某种形式的信令会更好,例如设置每个线程将以perioidic间隔轮询的ManualResetEvent
。或者,您可以使用支持任务取消的BackgroundWorker
类(在其上调用CancelAsync
,并使工作线程定期测试CancellationPending
)。如果您使用的是.NET 4.0,则还可以使用TPL。
答案 1 :(得分:1)
我建议你看一下内置的同步原语,比如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;
}
}
}
}
答案 2 :(得分:1)
其他人给出了答案的长版本,但显而易见的简单解决方案是简单地跳过重新创建线程对象:
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中的线程using one these guides(我推荐Joseph Albahari's guide on aborting - 简而言之是C#的作者)而不是使用它方法,特别是在执行可能使对象处于意外状态的IO或数据库操作时。
答案 3 :(得分:0)
另外,请记住,在线程上调用Abort是邪恶的。你应该用一个布尔条件或类似的东西来停止线程。
检查一下:
http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation