加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Windows > 正文

Windows SuspendThread不? (GetThreadContext失败)

发布时间:2020-12-14 01:36:49 所属栏目:Windows 来源:网络整理
导读:我们有一个 Windows32应用程序,其中一个线程可以阻止另一个线程检查它 通过执行SuspendThread / GetThreadContext / ResumeThread来状态[PC等]. if (SuspendThread((HANDLE)hComputeThread[threadId])0) // freeze thread ThreadOperationFault("SuspendThre
我们有一个 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 source for the guts of GetThreadContext包含
当由于某种原因尝试获取线程状态失败时,第819行的访问被拒绝返回响应.我猜,但看起来Wine GetThreadStatus认为线程可能无法重复访问.在SuspendThead超出我之后为什么会这样,但是有代码.思考?

EDIT2:我再次撒谎.我说我们只看到了Wine的行为.不……我们现在发现了Vista Ultimate系统似乎产生了同样的错误(再次,很少).因此,看起来Wine和Windows就一个模糊的案例达成一致.似乎只是启用Sysinternals进程监控程序会加剧情况并导致问题出现在Windows XP 64上;我怀疑是Heisenbug. (进程监视器
甚至不存在于Wine-tasting(:-)机器或我用于开发的XP 64系统上.

到底是什么?

编辑3:2010年9月15日.我已经添加了仔细检查错误返回状态,而不会干扰代码,SuspendThread,ResumeThread和GetContext.我没有在Windows系统上看到任何这种行为的暗示,因为我这样做了.还没有回到Wine实验.

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将失败.我还没有精力建立一个关键的实验来测试这个假设.

解决方法

让我引用Richter / Nassare的“ Windows via C++ 5Ed”,这可能会有所启发:

DWORD SuspendThread(HANDLE hThread);

Any thread can call this function to
suspend another thread (as long as you
have the thread’s handle). It goes
without saying (but I’ll say it
anyway) that a thread can suspend
itself but cannot resume itself. Like
ResumeThread,SuspendThread returns
the thread’s previous suspend count. A
thread can be suspended as many as
MAXIMUM_SUSPEND_COUNT times (defined
as 127 in WinNT.h). Note that
SuspendThread is asynchronous with
respect to kernel-mode execution,but
user-mode execution does not occur
until the thread is resumed.

In real life,an application must be
careful when it calls SuspendThread
because you have no idea what the
thread might be doing when you attempt
to suspend it. If the thread is
attempting to allocate memory from a
heap,for example,the thread will
have a lock on the heap. As other
threads attempt to access the heap,
their execution will be halted until
the first thread is resumed.
SuspendThread is safe only if you know
exactly what the target thread is (or
might be doing) and you take extreme
measures to avoid problems or
deadlocks caused by suspending the
thread.

Windows actually lets you look inside
a thread’s kernel object and grab its
current set of CPU registers. To do
this,you simply call
GetThreadContext:

BOOL GetThreadContext( HANDLE
hThread,PCONTEXT pContext);

To call this function,just allocate a
CONTEXT structure,initialize some
flags (the structure’s ContextFlags
member) indicating which registers you
want to get back,and pass the address
of the structure to GetThreadContext.
The function then fills in the members
you’ve requested.

You should call SuspendThread before
calling GetThreadContext; otherwise,
the thread might be scheduled and the
thread’s context might be different
from what you get back. A thread
actually has two contexts: user mode
and kernel mode. GetThreadContext can
return only the user-mode context of a
thread. If you call SuspendThread to
stop a thread but that thread is
currently executing in kernel mode,
its user-mode context is stable even
though SuspendThread hasn’t actually
suspended the thread yet. But the
thread cannot execute any more
user-mode code until it is resumed,so
you can safely consider the thread
suspended and GetThreadContext will
work.

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

也许在多核系统上,一个核心是处理用户模式刚刚挂起的线程的内核模式执行,保持锁定线程的CONTEXT结构,正好在另一个核心调用GetThreadContext时.

由于没有记录此行为,我建议联系microsoft.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读