C#挂起所有线程

时间:2013-08-17 06:37:10

标签: c# multithreading thread-safety remote-debugging visual-studio-debugging

我有一个可能相当独特的问题。我有一个应用程序,当我不在场时长时间在无头盒子上运行,但并不重要。我希望能够使用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();

这个想法就是这样,当我离开时我遇到了错误,应用程序有效地暂停了自己并等待远程调试器附加,这在第一次继续后自动获得正确的上下文归功于{{1}打电话。

问题在于:实施Debugger.Break变得非常重要。不推荐SuspendAllButCurrentThread,我不能P / Invoke到Thread.Suspend,因为托管线程和本机线程之间没有一对一的映射(因为我需要保持当前线程处于活动状态)。如果可以避免,我不想在有问题的机器上安装Visual Studio。我怎样才能做到这一点?

2 个答案:

答案 0 :(得分:5)

  

我不能P / Invoke到SuspendThread,因为托管线程和本机线程之间没有一对一的映射

您也不能枚举托管线程,只能枚举非托管线程。实际上 是他们之间的一对一映射,他们只是很难找到它。最初的目的是允许创建一个没有使用操作系统线程来实现Thread的自定义CLR主机,这是一个想要使用光纤的SQL Server组的请求。从来没有成功,他们无法让它足够可靠。没有实际的CLR主机不会使用真正的操作系统线程。

所以你实际上可以使用Process.GetCurrentProcess()。线程来枚举你所有的线程。并避免通过调用GetCurrentThreadId()来挂起你自己的,将它与ProcessThread.Id进行比较

这样做的可靠性是一种猜测,不要尝试做任何任何事情如发送警报以提醒您是时候连接调试器了。您可能已经暂停了在Windows中执行代码并获得全局锁定的线程。以及CLR工作线程,如终结器线程或后台GC线程。

更好的方法是使用一个单独的保护进程来完成所有这些,就像调试器一样。使用您在后台程序中创建的命名EventWaitHandle和主程序中的OpenExisting()。保护程序需要等待句柄以及进程的WaitAny()。你的主程序现在可以简单地调用Set()来唤醒守卫程序。现在可以安全地暂停所有线程。

答案 1 :(得分:1)

Thread.Suspend的主要问题是它可能会使某些对象处于不可用状态。

来自documentation

  

不要使用Suspend和Resume方法来同步   线程的活动。你无法知道一个线程是什么代码   暂停时正在执行。如果你暂停一个线程   在安全权限评估期间持有锁,其他线程在   AppDomain可能被阻止。如果你暂停一个线程   执行一个类构造函数,AppDomain中的其他线程   尝试使用该类被阻止。死锁可能会发生   容易。

因此,当您尝试查看此类尚未使用的对象的内容时,您可能也会被锁定。因此,无论您使用什么来暂停其他线程,您都可能在同一场景中结束。因此,唯一的可能性是修改其他线程的实现,以便能够让它们自行暂停:Is there a way to indefinitely pause a thread?