跨线程异常抛出
Posted
技术标签:
【中文标题】跨线程异常抛出【英文标题】:Cross-thread exception throwing 【发布时间】:2009-01-15 18:26:55 【问题描述】:我有一个应用程序,它允许用户使用我们自己制作的语言编写自己的代码,这种语言有点像 C++。然而,我们遇到了一些问题,有时我们的用户会不小心将无限循环写入他们的脚本。一旦脚本进入无限循环,他们唯一能摆脱的方法就是关闭应用程序并重新启动,这可能会丢失他们的工作。我想添加一些方法,当用户意识到他的代码处于无限循环中时,可以点击一个特殊的键,比如 F10 或其他什么,代码就会跳出循环。但我想在脚本运行时不实施大量检查的情况下做到这一点。最理想的情况是,我希望有一个单独的“调试器”线程,该线程主要是空闲的,但作为它的任务之一,它侦听 F10 键,当它获得 F10 键时,它将导致脚本运行时线程抛出异常,以便它停止执行脚本。所以我的问题是,有没有办法让一个线程导致另一个线程抛出异常?我的应用程序是用 C++ 编写的。
【问题讨论】:
【参考方案1】:如果脚本实际上是由您的应用程序解释的,那么您只需告诉解释器在发生某些用户事件时停止执行。
【讨论】:
【参考方案2】:这是可能的。例如,在单独的线程、隐藏窗口和 WM_HOTKEY 中检测击键。调用 SuspendThread() 以冻结解释器线程。现在使用 GetThreadContext() 来获取解释器线程的 CPU 寄存器。修改CONTEXT.Eip为函数地址,调用SetThreadContext()。让该函数调用 RaiseException() 或抛出 C++ 异常。 ResumeThread() 和繁荣。
【讨论】:
【参考方案3】:一个简短的回答 - 不。
如果您的应用程序在 Windows 上运行,也许您可以从这个“调试器”线程发送一条消息,并在主线程中有一个消息循环?
【讨论】:
【参考方案4】:该解决方案的问题是,要执行消息发送实现,我必须设置一个“侦听器”作为脚本解释器的一部分。现在,解释器只是执行函数。消息循环在解释器之外实现。如果在函数中存在无限循环,那么要跳出该脚本,我必须在解释器中执行每条指令之间检查一条消息,即 while(更多指令)检查 F10,执行脚本指令。这似乎有很多额外的不必要的检查会减慢脚本的执行速度。但如果这是唯一的解决方案,那么我想这就是它必须的。我仍然认为必须有更好的方法。也许脚本解释器需要在子线程上运行,而主线程继续它的消息循环,然后当它获得 F10 时将终止脚本解释器线程。
【讨论】:
“该解决方案的问题是,要执行消息发送实现,我必须设置一个“侦听器”作为脚本解释器的一部分”听起来很像“我想要这个新的功能,但我不想更改代码来获取它。”抱歉,我认为您需要更改代码。【参考方案5】:无论您是否明确编码,您都需要检查消息循环中的“中断”变量。如果你通过一个简单的volatile int
来实现它,你将拥有一个非常简单的测试和很少的开销。
【讨论】:
【参考方案6】:终止线程是不安全的,因为它可能正在使用整个进程共享的资源。
终止整个进程不太安全,但这对您没有帮助。
更安全的处理方法是让解释器定期检查事件并将停止事件视为终止事件(或至少溢出到更高的循环)。
对于 Windows,您还可以将 APC 排队到调用 RaiseException(...)
或抛出异常的线程(虽然我会避免后者,因为它跨越 API 边界),但这也意味着线程将把自己进入警戒状态。而且我真的不推荐它。
【讨论】:
以上是关于跨线程异常抛出的主要内容,如果未能解决你的问题,请参考以下文章