如何中止多个线程?

时间:2010-11-15 10:26:30

标签: c# .net winforms multithreading thread-abort

在此代码中,当单击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();
}

4 个答案:

答案 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