1

以下のコードは、問題の説明のみを目的としています。CodeDom を使用してソースをコンパイルする部分は無視してください。また、試してみると、「他のプロセス」の実行可能ファイルが実行されたままになり、CPU時間が無駄に消費されます。

本当の問題は、スレッドを開始してからスレッドを中止し、「スレッド中止が開始されました」というメッセージが表示され、

タイプ 'System.Threading.ThreadAbortException' の初回例外が mscorlib.dll で発生しました

デバッガー出力にメッセージが表示されますが、どちらcatchfinallyブロックも呼び出されず、それらのブロックからの出力はありません。

もちろん、リダイレクトされた出力を処理するために作成された余分なスレッドは中止されないため、プログラムは永久にハングしますが...

なぜ呼び出され、呼び出さcatchfinallyないのですか?

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 ) {
                }
            }
        }";
  }
}
4

2 に答える 2

3

問題はWaitForExit通話です。このマネージド コールは、最終的にネイティブ フレームで底をつきます。スレッドがネイティブ コード内にあるときにAbort呼び出しが発生した場合、スレッドがマネージ コードに戻るまで実際には何も起こりません。この場合、スレッドはプロセスが終了するのを待っているため、プロセスを物理的に強制終了するまで実際には戻りません

注: 例外がスローされたとしても、catchブロックは実際にはそれをキャッチしません。例外はブロックの最後で再スローされます。ResetAbortそれをキャッチしてメソッドを呼び出す必要があります

于 2014-02-12T16:53:03.693 に答える
2

ここで読むことができます:

ThreadAbortException は、キャッチできる特別な例外ですが、catch ブロックの最後で自動的に再度発生します。この例外が発生すると、ランタイムはスレッドを終了する前にすべての finally ブロックを実行します。

また、メソッド全体を try 内にラップする必要があると思います。

または、abort の呼び出しの前に外部プロセスが終了し、catch を含むメソッド (threadFunc と呼ばれるメソッド) が実行されなくなったと思いますか?

于 2014-02-12T16:50:38.283 に答える