6

私はかなりユニークな問題があります。私は存在しないときに長時間ヘッドレスボックスで動作するアプリケーションを持っていますが、重要ではありません。 Visual Studioを使用してこのアプリケーションをリモートでデバッグできるようにしたいと考えています。そのために、私はこのようなコードを持っている:C#すべてのスレッドを中断する

// 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(); 

私は離れていて、アプリケーションが効果的に自分自身を一時停止し、リモートデバッガ付けるのを待ちながら、この方法は、私はエラーを打つということでアイデアこれは最初のcontinueの後にDebugger.Breakコールのおかげで自動的に適切なコンテキストを取得します。

ここに問題があります:SuspendAllButCurrentThreadの実装は重要ではないことが判明しました。 Thread.Suspendは推奨されておらず、SuspendThreadにP/Invokeすることはできません。管理スレッドとネイティブスレッドの間に1対1のマッピングがないからです(現在のスレッドを生かしておく必要があるため)。おそらく避けることができれば、問題のマシンにVisual Studioをインストールしたくありません。どうすればこの作品を作れますか?

+0

おそらく、愚かな質問かもしれませんが、VSは、これらのフープを飛び越える必要なく、リモートデバッグを許可していませんか?私はいつもコード変更なしでリモートでデバッグできると思っていましたが、私はローカルでデバッグしたことを認めなければなりません – Surfbutler

答えて

5

私はP/SuspendThreadまで呼び出すことはできません、管理スレッドとネイティブスレッド

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

実際には、Process.GetCurrentProcess()を使用してスレッドをすべて列挙します。そして、それが可能になるだろうことは推測ですどのように信頼性の高い、それことを思い出させるためにアラートを送信するよう抜本的なをしようとしません

ProcessThread.Id

と比較すること、GetCurrentThreadIdを()pinvokingすることにより、独自の中断を避けますデバッガをアタッチする時間です。あなたは、Windows内でコードを実行していて、グローバルロックを取得していたスレッドを停止している可能性があります。ファイナライザスレッドやバックグラウンドGCスレッドなど、CLRワーカースレッドと同様に

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

+0

グローバルロックを使ってWindows内で何かを一時停止すると仮定します。第2に、この例では、廃止された 'Thread.Suspend'を使用するのではなく、' SuspendThread'をP/Invokeするでしょうか? – Octavianus

+0

それを避けることはできません。これは、デバッガが常に別のプロセスでなければならない理由です。はい、それをピンボケします。 –

+0

さて、プロセス固有のグローバルロックを意味するのでしょうか? これとは別のデバッガの接続を通知するためにデバッガとして登録する方法はありますか? – Octavianus

1

Thread.Suspendの主な問題は、オブジェクトを使用できない状態にすることができることです。 documentationから

は、スレッドの 活動を同期させるために中断し、再開メソッドを使用しないでください。 スレッドを中断して実行中のスレッドを知る方法がありません。 がセキュリティ許可の評価中にロックを保持している間にスレッドを中断すると、 の他のスレッドがブロックされる可能性があります。 がクラスコンストラクタを実行中にスレッドを中断した場合、そのクラスを使用しようとしているAppDomain内の他のスレッドがブロックされます。デッドロックは非常に簡単に発生する可能性があります 。

このように使用できないオブジェクトの内容を表示しようとすると、ロックされている可能性があります。したがって、他のスレッドを中断するために使用するものに関係なく、同じシナリオで終了する可能性があります。したがって、唯一の可能性は、他のスレッドの実装を変更して、自分自身を中断するように要求することです:Is there a way to indefinitely pause a thread?

関連する問題