jjzjj

Windows SuspendThread 没有? (GetThreadContext 失败)

coder 2023-11-11 原文

我们有一个 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 下没有看到这种行为(至少在上周没有,我真的不知道在那之前发生了什么)......但我们一直在测试这个Ubuntu 10.x 上 Wine 下的 Windows 应用程序。 Wine source for the guts of GetThreadContext包含 当由于某种原因尝试获取线程状态失败时,第 819 行的访问被拒绝返回响应。我在猜测,但 Wine GetThreadStatus 似乎认为线程可能无法重复访问。为什么在 SuspendThead 之后那会是真的我无法理解,但是有代码。想法?

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

这到底是什么?

EDIT3:2010 年 9 月 15 日。我在不干扰 SuspendThread、ResumeThread 和 GetContext 的代码的情况下,对错误返回状态进行了仔细检查。自从我那样做以来,我还没有在 Windows 系统上看到这种行为的任何提示。还没有回到 Wine 实验。

2010 年 11 月:奇怪。似乎如果我在 VisualStudio 2005 下编译它,它在 Windows Vista 和 7 上会失败,但在更早的操作系统上不会。如果我在 VisualStudio 2010 下编译,它不会在任何地方失败。有人可能会指责 VisualStudio2005,但我怀疑存在位置敏感问题,VS 2005 和 VS 2010 中的不同优化器将代码放置在略有不同的位置。

2012 年 11 月:Saga 继续。我们在许多 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 可能会失败,而线程处于内核模式,此时内核正在锁定线程上下文 block 。

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

由于没有记录此行为,我建议联系 Microsoft。

关于Windows SuspendThread 没有? (GetThreadContext 失败),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3444190/

有关Windows SuspendThread 没有? (GetThreadContext 失败)的更多相关文章

  1. ruby - 难道Lua没有和Ruby的method_missing相媲美的东西吗? - 2

    我好像记得Lua有类似Ruby的method_missing的东西。还是我记错了? 最佳答案 表的metatable的__index和__newindex可以用于与Ruby的method_missing相同的效果。 关于ruby-难道Lua没有和Ruby的method_missing相媲美的东西吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7732154/

  2. ruby-on-rails - rails 目前在重启后没有安装 - 2

    我有一个奇怪的问题:我在rvm上安装了ruby​​onrails。一切正常,我可以创建项目。但是在我输入“railsnew”时重新启动后,我有“程序'rails'当前未安装。”。SystemUbuntu12.04ruby-v"1.9.3p194"gemlistactionmailer(3.2.5)actionpack(3.2.5)activemodel(3.2.5)activerecord(3.2.5)activeresource(3.2.5)activesupport(3.2.5)arel(3.0.2)builder(3.0.0)bundler(1.1.4)coffee-rails(

  3. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  4. ruby - 即使失败也继续进行多主机测试 - 2

    我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r

  5. 没有类的 Ruby 方法? - 2

    大家好!我想知道Ruby中未使用语法ClassName.method_name调用的方法是如何工作的。我头脑中的一些是puts、print、gets、chomp。可以在不使用点运算符的情况下调用这些方法。为什么是这样?他们来自哪里?我怎样才能看到这些方法的完整列表? 最佳答案 Kernel中的所有方法都可用于Object类的所有对象或从Object派生的任何类。您可以使用Kernel.instance_methods列出它们。 关于没有类的Ruby方法?,我们在StackOverflow

  6. ruby-on-rails - Rails 3,嵌套资源,没有路由匹配 [PUT] - 2

    我真的为这个而疯狂。我一直在搜索答案并尝试我找到的所有内容,包括相关问题和stackoverflow上的答案,但仍然无法正常工作。我正在使用嵌套资源,但无法使表单正常工作。我总是遇到错误,例如没有路线匹配[PUT]"/galleries/1/photos"表格在这里:/galleries/1/photos/1/edit路线.rbresources:galleriesdoresources:photosendresources:galleriesresources:photos照片Controller.rbdefnew@gallery=Gallery.find(params[:galle

  7. ruby-on-rails - 有没有办法为 CarrierWave/Fog 设置上传进度指示器? - 2

    我在Rails应用程序中使用CarrierWave/Fog将视频上传到AmazonS3。有没有办法判断上传的进度,让我可以显示上传进度如何? 最佳答案 CarrierWave和Fog本身没有这种功能;你需要一个前端uploader来显示进度。当我不得不解决这个问题时,我使用了jQueryfileupload因为我的堆栈中已经有jQuery。甚至还有apostonCarrierWaveintegration因此您只需按照那里的说明操作即可获得适用于您的应用的进度条。 关于ruby-on-r

  8. ruby - 没有类方法获取 Ruby 类名 - 2

    如何在Ruby中获取BasicObject实例的类名?例如,假设我有这个:classMyObjectSystem我怎样才能使这段代码成功?编辑:我发现Object的实例方法class被定义为returnrb_class_real(CLASS_OF(obj));。有什么方法可以从Ruby中使用它? 最佳答案 我花了一些时间研究irb并想出了这个:classBasicObjectdefclassklass=class这将为任何从BasicObject继承的对象提供一个#class您可以调用的方法。编辑评论中要求的进一步解释:假设你有对象

  9. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

    我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

  10. ruby - 没有轨道的 ActiveRecord 时区 - 2

    我在非Rails项目中使用ActiveRecord。在Rails中,我可以这样做:config.time_zone='EasternTime(US&Canada)'config.active_record.default_timezone='EasternTime(US&Canada)'但如果我不使用rails,我该如何设置时区? 最佳答案 ActiveRecord::Base.default_timezone='EasternTime(US&Canada)' 关于ruby-没有轨道的A

随机推荐