我们有一个 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");
极少数情况下,在多核系统上,GetThreadContext 返回错误代码 5(Windows 系统错误代码“访问被拒绝”)。
SuspendThread 文档似乎清楚地表明目标线程被挂起,如果没有返回错误。我们正在检查 SuspendThread 和 ResumeThread 的返回状态;他们从来没有抱怨过。
我怎么能挂起一个线程,但不能访问它的上下文?
这个博客 http://www.dcl.hpi.uni-potsdam.de/research/WRK/2009/01/what-does-suspendthread-really-do/
表明 SuspendThread 在返回时可能已经开始挂起另一个线程,但该线程尚未挂起。在这种情况下,我可以看到 GetThreadContext 会有问题,但这似乎是定义 SuspendThread 的愚蠢方式。(SuspendThread 的调用如何知道目标线程实际挂起的时间?)
编辑:我撒谎了。我说这是针对 Windows 的。
好吧,奇怪的事实是,我在 Windows XP 64 下看不到这种行为(至少在上周没有,而且我真的不知道在那之前发生了什么)......但我们一直在测试这个 Windows 应用程序Ubuntu 10.x 上的 Wine。当尝试获取线程状态由于某种原因失败时,GetThreadContext的核心的Wine 源在第 819 行包含访问拒绝返回响应。我在猜测,但 Wine GetThreadStatus 似乎认为一个线程可能无法重复访问。为什么在 SuspendThead 超出我的范围后这是真的,但是有代码。想法?
EDIT2:我又撒谎了。我说我们只看到了 Wine 上的行为。不……我们现在发现了一个似乎产生相同错误的 Vista Ultimate 系统(再次,很少)。因此,Wine 和 Windows 似乎就一个不起眼的案例达成了一致。似乎仅启用 Sysinternals Process 监控程序会使情况恶化并导致问题出现在 Windows XP 64 上;我怀疑是海森堡。(过程监视器甚至在我用于开发的品酒 (:-) 机器或 XP 64 系统上都不存在)。
它到底是什么?
EDIT3:2010 年 9 月 15 日。我已经对 SuspendThread、ResumeThread 和 GetContext 的错误返回状态进行了仔细检查,而不会干扰代码。自从我这样做以来,我没有在 Windows 系统上看到任何有关这种行为的迹象。还没有回到葡萄酒实验。
2010 年 11 月:奇怪。似乎如果我在 VisualStudio 2005 下编译它,它在 Windows Vista 和 7 上会失败,但在早期的操作系统上不会。如果我在 VisualStudio 2010 下编译,它不会在任何地方失败。有人可能会指责 VisualStudio2005,但我怀疑位置敏感问题,VS 2005 和 VS 2010 中的不同优化器将代码放置在稍微不同的位置。
2012 年 11 月:传奇继续。我们在许多 XP 和 Windows 7 机器上看到了这种故障,而且发生率非常低(每几千次运行一次)。我们的 Suspend 活动适用于主要执行纯计算代码但有时会调用 Windows 的线程。我不记得当线程的 PC 在我们的计算代码中时看到这个问题。当然,当线程挂起时我看不到线程的PC,因为GetContext不会给我,所以我无法直接确认问题只发生在执行系统调用时。但是,我们所有的系统调用都通过一个点进行引导,到目前为止,有证据表明,当我们遇到问题时,该点已被执行。因此,间接证据表明,只有在该线程正在执行系统调用时,线程上的 GetContext 才会失败。我没有