【问题标题】:Throw an exception into another thread向另一个线程抛出异常
【发布时间】:2016-07-28 19:19:38
【问题描述】:

这不是任何涉及从另一个线程中捕获一个线程中抛出的异常的问题的重复。

我有生成线程的代码,它会自行关闭并做自己的事情。

在未来的某个时候,我希望能够在另一个线程中抛出两个异常之一(即terminateinterrupt)。

一种方法是共享一个变量并让另一个线程定期检查它是否应该被杀死。我的偏好是没有它检查的约束(一些代码将独立于执行线程的库,并且不会被编写来检查)。

在我的理想解决方案中,您最终可能会遇到这样的情况:在调试时,您可能会发现 auto i = 1 + 1 抛出异常,因为另一个线程告诉您的线程抛出异常,而这正是您刚刚发生的情况 在那个时候开启。

有什么办法可以做到吗?

【问题讨论】:

  • 说实话,这真的没有任何意义。 C++ 的异常机制基本上是围绕展开发生异常的上下文堆栈进行组织的。或许你可以尝试解释你试图用这个机制解决的问题,你会得到关于解决它的明智方法的建议。通常的答案是这样的:“如果你发现你需要从外部进入以使线程做正确的事情,那意味着你为那个线程编写了错误的代码。为什么它没有被编码来做正确的事情? 所有线程必须合作。”
  • 在一个理想的世界里,是的,@DavidSchwartz,他们会的。但是,如果一个线程正在等待某个 API(例如 InfiniBand)返回而它永远不会返回,那么所有广告是否应该合作都没关系:它们不合作。假设你将永远处于这样的位置是幼稚的。
  • 肯定有工具可以处理这样的情况,但跨线程异常不是。如果 API 支持中断,您只需使用它支持的中断即可。如果它不支持中断,那么中断就不是解决方案。否则,您必须使用其他工具,例如使用包装器将 API 隔离到自己的进程。

标签: multithreading c++11 exception posix


【解决方案1】:

是的,可以在另一个线程中引发异常。

我假设您知道为什么不应该在正常程序中执行此操作的所有充分理由。但作为测试套件、调试工具或其他与 python 内部相关的程序的一部分,这可能会有所帮助。

这是解除的,大致来自https://gist.github.com/liuw/2407154

import ctypes

def ctype_async_raise(target_tid, exception):
    ret = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(target_tid), ctypes.py_object(exception))
    # ref: http://docs.python.org/c-api/init.html#PyThreadState_SetAsyncExc
    if ret == 0:
        raise ValueError("Invalid thread ID")
    elif ret > 1:
        # Huh? Why would we notify more than one threads?
        # Because we punch a hole into C level interpreter.
        # So it is better to clean up the mess.
        ctypes.pythonapi.PyThreadState_SetAsyncExc(target_tid, NULL)
        raise SystemError("PyThreadState_SetAsyncExc failed")

【讨论】:

  • 在 C++ 下是否可以在另一个线程中引发异常? AFAICT 提问者没有提到 python。
【解决方案2】:

我认为线程 A 中的异常被线程 B 捕获在概念上没有意义,因为异常的核心概念是堆栈的展开,并且线程 A 的堆栈与线程 B 的堆栈不同。

你可以做的是在线程 A 中抛出异常,让线程 A 中的异常处理程序捕获异常并通过以某种方式通知线程 B 相关详细信息来处理它,当线程 B 收到通知时可以通过抛出响应它自己的异常类似于最初在线程 A 中抛出的异常。

至于如何实现通知和数据传输,您可以使用任何常用的跨线程通知/通信机制(共享原子变量和轮询、套接字对、管道、互斥保护的 FIFO 消息队列等)。

在我的理想解决方案中,您最终可能会遇到这样的情况:调试, 您可能会发现 auto i = 1 + 1 会引发异常,因为另一个 线程告诉你的线程抛出,这就是你刚刚发生的那一行 在那个时候打开。

我认为这被称为异步异常,我认为标准 C++ 不支持它。微软有他们的structured exception handling (SEH) 可以做到这一点,但这是一个专有/非标准功能。

【讨论】:

  • 除了你的最后一段,我认为你完全没有抓住重点。 很多方法可以将某些内容从一个线程传递到另一个线程 - 如果另一个线程正在监听。但是如果另一个线程没有在监听(因为有人写了一个 API 会阻塞某些东西并且不等待),那没关系。关键不是在一个线程中抛出异常并在另一个线程中捕获它:而是将一个线程注入另一个线程。
  • 将我的答案更改为“不,这不可能”会更好吗? (顺便说一句,问题的标题是“向另一个线程抛出异常”,这对我来说听起来很像“在一个线程中抛出异常并在另一个线程中捕获它”)
  • 听起来很像,但不是真的。一个是throw Exception(),然后是另一个线程中的一个catch。另一个是otherThreadObject.throwException<Exception>()
猜你喜欢
  • 2012-01-11
  • 2022-01-09
  • 2011-06-25
  • 2022-09-28
  • 1970-01-01
  • 2011-11-14
  • 2015-02-23
  • 1970-01-01
  • 2018-09-18
相关资源
最近更新 更多