Windows SuspendThread不';T(GetThreadContext失败)

Windows SuspendThread不';T(GetThreadContext失败),windows,multithreading,winapi,suspend,Windows,Multithreading,Winapi,Suspend,我们有一个Windows32应用程序,其中一个线程可以停止另一个线程来检查其线程 通过执行SuspendThread/GetThreadContext/ResumeThread来声明[PC等] if (SuspendThread((HANDLE)hComputeThread[threadId])<0) // freeze thread ThreadOperationFault("SuspendThread","InterruptGranule"); CONTEXT Context,

我们有一个Windows32应用程序,其中一个线程可以停止另一个线程来检查其线程 通过执行SuspendThread/GetThreadContext/ResumeThread来声明[PC等]

if (SuspendThread((HANDLE)hComputeThread[threadId])<0)  // freeze thread
   ThreadOperationFault("SuspendThread","InterruptGranule");
CONTEXT Context, *pContext;
Context.ContextFlags = (CONTEXT_INTEGER | CONTEXT_CONTROL);
if (!GetThreadContext((HANDLE)hComputeThread[threadId],&Context))
   ThreadOperationFault("GetThreadContext","InterruptGranule");

if(SuspendThread((HANDLE)hComputeThread[threadId])在挂起一个拥有
CriticalSection
的线程时,会出现一些特殊的问题。我现在找不到一个很好的引用,但这里有。基本上,如果你在线程访问操作系统锁时不幸调用
SuspendThread
(例如,heap lock、
DllMain
lock等),然后可能会发生非常奇怪的事情。我假设您很少遇到这种情况


在处理器产生类似于睡眠(0)
的结果后,重试调用
GetThreadContext
是否有效?

让我引用Richter/Nassare的“”一文,这可能会有所启发:

DWORD SuspendThread(句柄hThread)

任何线程都可以调用此函数来 挂起另一个线程(只要 拿着线的手柄),它就走了 不用说(但我会说) 无论如何)线程可以挂起 但是不能恢复自己,就像 ResumeThread,SuspendThread返回 线程以前的挂起计数。A 线程可以挂起多达个线程 最大暂停计数次数(已定义) 如WinNT.h.中的127),请注意 SuspendThread与 关于内核模式执行,但是 不执行用户模式 直到线程恢复

在现实生活中,应用程序必须是 调用SuspendThread时要小心 因为你根本不知道 当您尝试时,线程可能正在执行 挂起它。如果线程 正在尝试从内存分配内存 例如,线程将 在堆上有一个锁 线程尝试访问堆, 他们的死刑将暂停执行,直到 第一个线程被恢复。 只有在您知道的情况下,SuspendThread才是安全的 目标线程是什么(或 可能正在做)而你采取极端的 避免问题或风险的措施 由于挂起 线

Windows实际上可以让您查看内部 线程的内核对象并获取其 CPU寄存器的当前设置。要执行的操作 这个,你只要打电话 GetThreadContext:

BOOL GetThreadContext(句柄 hThread,PCONTEXT,PCONTEXT)

要调用此函数,只需分配一个 上下文结构,初始化一些 flags(结构的ContextFlags 成员)指示您的注册号 想回去把地址传给我吗 将结构的属性设置为GetThreadContext。 然后,该函数填充成员 你已经要求了

您应该在之前调用SuspendThread 调用GetThreadContext;否则, 线程可能已调度,并且 线程的上下文可能不同 从你得到的,一根线 实际上有两个上下文:用户模式 和内核模式。GetThreadContext可以 仅返回用户模式的上下文 线程。如果调用SuspendThread 停止一个线程,但该线程是 当前在内核模式下执行, 它的用户模式上下文甚至是稳定的 虽然SuspendThread实际上没有 挂线了,但是 线程不能再执行了 用户模式代码,直到恢复,所以 你可以安全地考虑线程 挂起和GetThreadContext将 工作

我的猜测是,如果只是调用SuspendThread,那么GetThreadContext可能会失败,而线程处于内核模式,内核此时正在锁定线程上下文块

可能在多核系统上,一个内核正在处理其用户模式刚刚挂起的线程的内核模式执行,保持锁定线程的上下文结构,而另一个内核正在调用GetThreadContext


由于此行为没有文档记录,我建议与microsoft联系。

可能是线程安全问题。您确定hComputeThread结构没有从您下面更改吗?可能是在调用suspend时线程正在退出?这可能会导致挂起成功,但在调用get context时,它已消失,句柄已处于状态有效。

旧版本,但很高兴看到您在经历了2年多的问题后,仍然使用状态更改对其进行更新

问题的原因是x64版本WoW64的翻译层中存在错误,如下所示:

在WoW64下的GetThreadContext中有一个相当严重的错误,这使得它返回陈旧的内容,这使得它在许多情况下不可用。内容存储在用户模式下。这就是为什么您认为该值不是null,但在陈旧的内容中它仍然是null

这就是为什么它在较新的操作系统(而不是较旧的操作系统)上失败的原因,请尝试在Windows 7 32位操作系统上运行它

至于为什么在Visual Studio 2010/2012上构建的解决方案中出现此错误的频率较低,可能是编译器正在做的某些事情缓解了大部分问题,为此,您应该检查2005年和2010年生成的IL,看看有什么不同。例如,如果JET是在没有优化的情况下构建的吗

最后,进一步阅读:


如果调用线程试图获取挂起线程所拥有的同步对象,则在拥有同步对象的线程上调用SuspendThread,例如互斥对象或关键部分,可能会导致死锁。
-MSDN

AFAIK,线程是否拥有CriticalSection并不重要。如果挂起它,则挂起它拥有CriticalSection;这并不比挂起拥有另一个资源(例如,动态分配的存储块)更糟糕除非挂起程序试图使用该资源。我们没有这样做…你建议哪个线程正在进行睡眠(0)