在中止线程的单独线程中的任务行为

时间:2017-12-13 14:04:50

标签: c# multithreading parallel.foreach

我有一个特殊的线程设置和Parallel.Foreach:在一个单独的线程中执行Parallel.Foreach循环。通过调用函数Thread可能会中止Abort()。我得到了奇怪的行为:多次ThreadAbortException被抛出。有人可以解释这里发生了什么,什么是一个好的解决方案?

系统:

  • Visual Studio 2017
  • C#7.0
  • .Net 4.6.1

以下代码。

static void Main(string[] args)
    {
        //Start the new Thread
        Thread workerThread = new Thread(Program.TestVoid);
        workerThread.Name = "My WorkerThread";
        workerThread.Start();

        //wait
        Thread.Sleep(1000);

        //abort thread
        workerThread.Abort();
    }

    public static void TestVoid()
    {
        bool[] liBools = new bool[10000];

        Parallel.For(0, liBools.Length, idx =>
        {
            liBools[idx] = idx == 9998;
        });

        try
        {
            Parallel.ForEach(liBools, myBool =>
            {
                try
                {
                    //do something
                    Thread.Sleep(1000);
                }
                catch (Exception ex) //Thread Abort Exception get caught
                {

                }
            });
        }
        catch (OperationCanceledException ex)
        {

        }
        catch (ThreadAbortException ex) //Thread Abort Exception get caught
        {

        } //here arises another ThreadAbortException
        finally
        {
            source.Dispose();
        }
        string s = "ready";
    }

2 个答案:

答案 0 :(得分:2)

  

我得到一个奇怪的行为:多次ThreadAbortException被抛出。

这是该例外的正常行为:

  

当调用Abort方法来销毁线程时,公共语言运行库会抛出ThreadAbortException。 ThreadAbortException是一个可以捕获的特殊异常,但它会在catch块的末尾自动再次引发。引发此异常时,运行时会在结束线程之前执行所有finally块。因为线程可以在finally块中执行无限制计算或调用Thread.ResetAbort来取消中止,所以无法保证线程将永远结束。如果要等到中止的线程结束,可以调用Thread.Join方法。 Join是一个阻塞调用,在线程实际停止执行之前不会返回。 (Source

  

什么是一个好的解决方案

您可以使用Thread.ResetAbort()取消此时的堕胎,但如果您不致电Thread.Abort(),则几乎总是更好。可取消的Task和检查不稳定的“请立即停止”布尔值是两种选择。其他可能适用于您的用例。 Thread.Abort()只应保留为按下大红色警报按钮的情况,如果有的话。

答案 1 :(得分:0)

如果查看documentation for Thread.Abort,您会看到其功能是抛出ThreadAbortException。如果那不是您想要的,请不要使用Thread.Abort。通常,您应该通过从其整个调用堆栈正常完成/返回而不是调用Thread.Abort来退出线程。如果您必须致电Thread.Abort,您应该准备好处理与之相关的异常。