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

这样的想法是,当我离开时,我遇到了一个错误,应用程序有效地暂停并等待远程调试器附加,在第一次 continue 之后,由于Debugger.Break调用,它会自动获取正确的上下文。

问题是:实施SuspendAllButCurrentThread结果证明是不平凡的。Thread.Suspend已弃用,并且我无法 P/Invoke 到,SuspendThread因为托管线程和本机线程之间没有一对一的映射(因为我需要保持当前线程处于活动状态)。如果可以避免的话,我不想在有问题的机器上安装 Visual Studio。我怎样才能使这项工作?

4

2 回答 2

5

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

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

因此,您实际上可以使用 Process.GetCurrentProcess().Threads 来枚举所有线程。并避免通过调用 GetCurrentThreadId() 来暂停您自己的操作,并将其与 ProcessThread.Id 进行比较

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

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

于 2013-08-17T10:12:42.100 回答
1

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

文档中:

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

因此,当您尝试查看此类但无法使用的对象的内容时,您可能也会被锁定。因此,无论您使用什么来挂起其他线程,您最终都可能会遇到相同的情况。因此,唯一的可能性是修改其他线程的实现,以便能够要求它们暂停自己:有没有办法无限期暂停一个线程?.

于 2013-08-17T09:27:31.243 回答