不,实际上出于与如果我知道实际数量,如何构建 ThreadId? https://stackoverflow.com/questions/24995262/how-can-i-build-a-threadid-given-that-i-know-the-actual-number:图书馆根本不给你任何东西来获取ThreadId
所有(仍在运行的)线程或任何其他工具可以在不属于您的任何线程上工作。
此外,您无法可靠地猜测哪些线程是由forkIO
属于您的 GHCi 会话(所有评估通常都在沙盒中forkIO
)、底层 yesod 应用程序,或者线程化 RTS(它至少有一个对forkIO
- 这基本上确保所有事件管理器都被关闭)。目前,这还不算太糟糕,因为 GHCi 运行在main
如果无论如何关闭,线程和 IO 管理器都会重新启动,但这在未来的版本中可能会改变。
那么为什么线程在终止时会被收集呢?hs_exit() https://github.com/ghc/ghc/blob/c1336f71dbd80b66643e65fc7d5df0cc8fe9942b/rts/RtsStartup.c#L305-L437。本质上,它调用ioManagerDie()
(杀死所有活动经理 https://ghc.haskell.org/trac/ghc/wiki/Commentary/Rts/IOManager) and exitScheduler(..)
(see 调度程序 https://ghc.haskell.org/trac/ghc/wiki/Commentary/Rts/Scheduler,这基本上杀死所有线程 https://github.com/ghc/ghc/blob/f6866824ce5cdf5359f0cad78c49d65f6d43af12/rts/Schedule.c#L2463-L2488。这些函数都没有合适的 FFI 包装器。
当时hs_exit()
被称为,main
Haskell 世界已经结束了。由于这些函数中没有一个具有适当的等效项GHC.*
模块,你不能直接在 Haskell 中调用它们,因此在 GHCi 中也不能直接调用它们,因为没有合适的:#
命令。
所以总而言之,你不能。如果在 GHCi 中添加一个命令来重新启动调度程序,那就太简单了。但鉴于调度程序开始于hs_init()
并停在hs_exit()
in the 即时战略模型 https://ghc.haskell.org/trac/ghc/wiki/Commentary/Rts,我怀疑这是否是一个简单的扩展。
不过,根据您想做什么,您可以作弊。你可以自己写forkIOMem
,它存储ThreadId
在全球范围内MVar
,并替换所有forkIO
在来源中。那可以是very很麻烦,特别是如果您正在使用图书馆,因为您需要确保forkIO
被替换到处.
You could, of course, meddle with the base
package, but that's probably madness (still possible though), change forkIO
there and add killAllforkIOs
to Control.Concurrent
. (I've already said that this is probably madness, right?)