6

かなりユニークな問題があります。私が不在のときにヘッドレス ボックスで長時間実行されるアプリケーションがありますが、重要ではありません。Visual Studio を使用して、このアプリケーションをリモートでデバッグできるようにしたいと考えています。そうするために、次のようなコードがあります。

// Suspend all other threads to prevent loss
// of state while we investigate the issue.
SuspendAllButCurrentThread();
var remoteDebuggerProcess = new Process
    {
        StartInfo =
            {
                UseShellExecute = true,
                FileName = MsVsMonPath;
            }
    };
// Exception handling and early return removed here for brevity.
remoteDebuggerProcess.Start();

// Wait for a debugger attach.
while (!Debugger.IsAttached)
{
    Thread.Sleep(500);
}
Debugger.Break();

// Once we get here, we've hit continue in the debugger. Restore all of our threads,
// then get rid of the remote debugging tools.
ResumeAllButCurrentThread();

remoteDebuggerProcess.CloseMainWindow();
remoteDebuggerProcess.WaitForExit();

このように、離れている間にエラーが発生すると、アプリケーションは効果的に一時停止し、リモート デバッガーのアタッチを待機します。リモート デバッガーのアタッチは、最初の継続の後、Debugger.Break呼び出しのおかげで適切なコンテキストを自動的に取得します。

ここに問題があります: 実装SuspendAllButCurrentThreadは自明ではありません。マネージド スレッドとネイティブ スレッドの間に 1 対 1 のマッピングがないため (現在のスレッドを維持する必要があるため)、Thread.SuspendP/Invoke をダウンさせることはできません。SuspendThread回避できる可能性がある場合、問題のマシンに Visual Studio をインストールしたくありません。どうすればこれを機能させることができますか?

4

2 に答える 2

5

マネージ スレッドとネイティブ スレッドの間に 1 対 1 のマッピングがないため、SuspendThread まで P/Invoke できません。

マネージド スレッドも列挙できず、アンマネージド スレッドのみを列挙できます。実際に、それらの間には 1 対 1 のマッピングがあり、見つけるのが難しくなっています。当初の目的は、オペレーティング システム スレッドを使用せずにスレッドを実装するカスタム CLR ホストを作成できるようにすることでした。これは、代わりにファイバーを使用したいという SQL Server グループからの要求でした。それは決してうまくいきませんでした.彼らはそれを十分に信頼できるものにすることができませんでした. 実際のオペレーティング システム スレッドを使用しない実際の CLR ホストは存在しません。

したがって、実際には Process.GetCurrentProcess().Threads を使用してすべてのスレッドを列挙できます。また、GetCurrentThreadId() をピンボークし、それを ProcessThread.Id と比較して、独自のものを一時停止しないようにします。

それがどれほど信頼できるものになるかは推測ですが、デバッガーをアタッチする時が来たことを知らせるアラートを送信するなど、抜本的なことをしよとしないでください。Windows 内でコードを実行していたスレッドを中断し、グローバル ロックを取得した可能性があります。ファイナライザー スレッドやバックグラウンド GC スレッドなどの CLR ワーカー スレッド。

より良いアプローチは、デバッガーと同じように、これらすべてを行う別のガード プロセスを使用することです。ガード プログラムで作成した名前付き EventWaitHandle と、メイン プログラムで OpenExisting() を使用します。ガード プログラムは、その待機ハンドルとプロセスに対して WaitAny() を実行する必要があります。メイン プログラムは Set() を呼び出すだけでガード プログラムを起動できます。すべてのスレッドを安全に中断できるようになりました。

于 2013-08-17T10:12:42.100 に答える