// 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是非常重要的.不推荐使用Thread.Suspend,我不能P / Invoke到SuspendThread,因为托管线程和本机线程之间没有一对一的映射(因为我需要保持当前线程处于活动状态).如果可以避免,我不想在有问题的机器上安装Visual Studio.我怎样才能做到这一点?
解决方法
I can’t P/Invoke down to SuspendThread because there’s no one-to-one mapping between managed threads and native threads
您也不能枚举托管线程,只能枚举非托管线程.实际上它们之间存在一对一的映射,它们只是很难找到它.最初的目的是允许创建一个不使用操作系统线程来实现Thread的自定义CLR主机,这是sql Server组要求使用光纤的请求.从来没有成功,他们无法让它足够可靠.不存在不使用实际操作系统线程的实际CLR主机.
所以你实际上可以使用Process.GetCurrentProcess().线程来枚举你所有的线程.并避免通过pinvoking GetCurrentThreadId()暂停您自己的,将它与ProcessThread.Id进行比较
这样做的可靠性是一种猜测,不要试图做任何激烈的事情,如发送警报提醒您是时候连接调试器了.您可能已经暂停了在Windows中执行代码并获得全局锁定的线程.以及CLR工作线程,如终结器线程或后台GC线程.
更好的方法是使用一个单独的保护进程来完成所有这些,就像调试器一样.使用您在后台程序中创建的命名EventWaitHandle和主程序中的OpenExisting().保护程序需要等待句柄以及进程的WaitAny().你的主程序现在可以简单地调用Set()来唤醒守卫程序.现在可以安全地暂停所有线程.