基于my previous question我想询问是否有办法在GHCi会话中杀死所有用户创建的线程?
原因是当一个函数退出GHCi时,它产生的线程不会自动终止,即使通过代码重新加载也会持久化。重新启动GHCi可以解决这个问题,但是由于我的应用程序需要一段时间才能加载,所以如果有可能(甚至是hacky)的解决方法,这将是很好的。
答案 0 :(得分:4)
不,实际上和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()
。从本质上讲,它会调用ioManagerDie()
(删除所有event managers)和exitScheduler(..)
(请参阅scheduler,基本上kills all threads。这些函数都没有适当的FFI包装。
在调用hs_exit()
时,来自Haskell世界的main
已经完成。由于这些函数中没有一个在GHC.*
模块中具有适当的等价物,因此不能直接在Haskell中调用它们,因此在GHCi中,因为没有合适的:#
命令。
总而言之,你做不到。如果要添加一个命令来重新启动GHCi中的调度程序,那就很容易了。但鉴于调度程序已在hs_init()
中启动并在RTS model的hs_exit()
中停止,我怀疑这是一个简单的扩展。
根据您的想法,您可以作弊。您可以编写自己的forkIOMem
,将ThreadId
存储在全局MVar
中,并替换源中的所有forkIO
。这可能非常很麻烦,特别是如果您正在使用库,因为您需要确保{em>在任何地方替换forkIO
。
当然,你可以插入base
包,但这可能是疯狂的(尽管仍然可能),在那里更改forkIO
并将killAllforkIOs
添加到Control.Concurrent
。 (我已经说过这可能是疯了,对吧?)