C# 为什么这段代码中没有捕获到ThreadAbortException,它有两个进程和输出重定向?

C# 为什么这段代码中没有捕获到ThreadAbortException,它有两个进程和输出重定向?,c#,.net,try-catch-finally,threadabortexception,C#,.net,Try Catch Finally,Threadabortexception,我有下面的代码,只是为了说明问题。请忽略使用CodeDom编译源代码的部分。此外,如果您尝试它,它会让“其他进程”可执行文件运行,并且会浪费CPU时间 真正的问题是我启动线程,然后中止线程,并看到“ThreadAbortInitiated”消息,然后 mscorlib.dll中首次出现类型为“System.Threading.ThreadAbortException”的异常 调试器输出中的消息,但不会调用catch或finally块,并且这些块没有输出 当然,由于为处理重定向输出而创建的额外线程

我有下面的代码,只是为了说明问题。请忽略使用CodeDom编译源代码的部分。此外,如果您尝试它,它会让“其他进程”可执行文件运行,并且会浪费CPU时间

真正的问题是我启动线程,然后中止线程,并看到“ThreadAbortInitiated”消息,然后

mscorlib.dll中首次出现类型为“System.Threading.ThreadAbortException”的异常

调试器输出中的消息,但不会调用
catch
finally
块,并且这些块没有输出

当然,由于为处理重定向输出而创建的额外线程不会中止,程序将永远挂起,但是

为什么
catch
最终不被调用

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Diagnostics;
using Microsoft.CSharp;
using System.CodeDom.Compiler;

namespace ConsoleApplication
{
  class Program
  {
    static void Main(string[] args)
    {
      new Program().payload();
    }

    private void payload()
    {
      var otherExecutableName = "OtherProcess.exe";
      compileOtherProcessExecutable(otherExecutableName);
      var thread = new System.Threading.Thread(() => threadFunc(otherExecutableName));
      thread.Start();
      Thread.Sleep( 1000 );
      thread.Abort();
      Debug.WriteLine("Thread abort initiated");
    }

    private void threadFunc( String secondExecutableName )
    {
        Process process = null;
        try {
            process = new Process();
            {
                process.StartInfo.FileName = secondExecutableName;
                process.StartInfo.UseShellExecute = false;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardError = true;

                process.OutputDataReceived += new DataReceivedEventHandler(outputHandler);
                process.ErrorDataReceived += new DataReceivedEventHandler(outputHandler);

                process.Start();

                process.BeginOutputReadLine();
                process.BeginErrorReadLine();

                process.WaitForExit();
            }
        } catch( Exception e ) {
            Debug.WriteLine( "Catch block: " + e.Message );
        } finally {
            Debug.WriteLine( "Finally block" );
            if( process != null ) {
                process.Kill();
                Debug.WriteLine( "Process killed" );
            }
        }
    }

    static void compileOtherProcessExecutable(string filePath)
    {
        using (var compiler = new CSharpCodeProvider())
        {
            var parameters = new CompilerParameters(null, filePath, true);
            parameters.GenerateExecutable = true;
            var compResult = compiler.CompileAssemblyFromSource( parameters, otherProcessCode);
            var errs = compResult.Errors;
            if (errs.HasErrors)
            {
                var err = errs.Cast<CompilerError>().First();
                throw new InvalidOperationException(String.Format(
                    "Compilation failed. Line {0}: {1}", err.Line, err.ErrorText));
            }
        }
    }

    private void outputHandler(object process, DataReceivedEventArgs output)
    {
    }

    static readonly String otherProcessCode =
        @"class Program {
            public static void Main(string[] args)
            {
                while( true ) {
                }
            }
        }";
  }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
使用系统线程;
使用系统诊断;
使用Microsoft.CSharp;
使用System.CodeDom.Compiler;
命名空间控制台应用程序
{
班级计划
{
静态void Main(字符串[]参数)
{
新程序().payload();
}
私有无效有效载荷()
{
var otherExecutableName=“OtherProcess.exe”;
compileOtherProcessExecutable(其他ExecutableName);
var thread=new System.Threading.thread(()=>threadFunc(otherExecutableName));
thread.Start();
睡眠(1000);
thread.Abort();
WriteLine(“线程中止启动”);
}
私有void threadFunc(字符串secondExecutableName)
{
Process=null;
试一试{
流程=新流程();
{
process.StartInfo.FileName=secondExecutableName;
process.StartInfo.UseShellExecute=false;
process.StartInfo.RedirectStandardOutput=true;
process.StartInfo.RedirectStandardError=true;
process.OutputDataReceived+=新的DataReceivedEventHandler(outputHandler);
process.ErrorDataReceived+=新的DataReceivedEventHandler(outputHandler);
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
}
}捕获(例外e){
Debug.WriteLine(“Catch块:+e.Message”);
}最后{
WriteLine(“Finally block”);
if(进程!=null){
process.Kill();
Debug.WriteLine(“进程终止”);
}
}
}
静态void compileOtherProcessExecutable(字符串文件路径)
{
使用(var compiler=new CSharpCodeProvider())
{
var参数=新的编译器参数(null,filePath,true);
parameters.GenerateExecutable=true;
var compressult=compiler.compileasemblyfromsource(参数、其他过程代码);
var errs=压缩结果错误;
if(errs.HasErrors)
{
var err=errs.Cast().First();
抛出新的InvalidOperationException(String.Format(
“编译失败。行{0}:{1}”,err.Line,err.ErrorText));
}
}
}
私有void输出处理器(对象进程、DataReceivedEventArgs输出)
{
}
静态只读字符串otherProcessCode=
@“班级计划{
公共静态void Main(字符串[]args)
{
while(true){
}
}
}";
}
}
您可以阅读:

ThreadAbortException是一个可以捕获的特殊异常,但它将在catch块结束时自动再次引发。当引发此异常时,运行库在结束线程之前执行所有finally块

但是,我认为您应该将整个方法包装在try中

或者,您是否认为您的外部进程可能在调用abort之前已经完成,因此带有catch的方法threadFunc不再执行?

您可以阅读:

ThreadAbortException是一个可以捕获的特殊异常,但它将在catch块结束时自动再次引发。当引发此异常时,运行库在结束线程之前执行所有finally块

但是,我认为您应该将整个方法包装在try中


或者,您是否认为您的外部进程可能在调用abort之前完成,因此带有catch的方法threadFunc不再执行?

问题在于
WaitForExit
调用。这个托管调用最终将在本机框架中见底。当线程在本机代码中时发生
Abort
调用时,在线程返回托管代码之前,实际上不会发生任何事情。在这种情况下,线程正在等待进程完成,因此在实际终止进程之前不会返回


注意:即使抛出异常,
catch
块实际上也不会捕获它。该异常将在块的末尾重新调用。您需要捕获它并调用
ResetAbort
方法

问题在于
WaitForExit
调用。这个托管调用最终将在本机框架中见底。当线程在本机代码中时发生
Abort
调用时,在线程返回托管代码之前,实际上不会发生任何事情。在这种情况下,线程正在等待进程完成,因此在实际终止进程之前不会返回

注意:即使抛出异常,
catch
块实际上也不会捕获它。该异常将在块的末尾重新调用。您需要捕获它并调用
ResetAbort