Ответ 1
Нет, и фактически почти по тем же причинам, что и в Как я могу построить ThreadId, учитывая, что я знаю фактическое число?: Библиотека просто не дает вам все, чтобы получить ThreadId
всех (все еще запущенных) потоков или любого другого объекта для работы с любыми потоками, которые не принадлежат вам.
Кроме того, вы не можете надежно угадать, какие потоки, порожденные с помощью forkIO
, относятся к вашему сеансу GHCi (все оценки обычно изолированы в формате forkIO
), базовом приложении yesod или в потоковом RTS (который имеет хотя бы один вызов до forkIO
, что в основном гарантирует закрытие всех менеджеров событий). В настоящее время это не так уж плохо, поскольку GHCi работает в потоке main
, и диспетчер ввода-вывода перезапускается, если он выключен в любом случае, но это может измениться в будущих версиях.
Итак, почему потоки даже собираются при завершении? hs_exit()
. По существу, он вызывает ioManagerDie()
(убивает всех менеджеров событий) и exitScheduler(..)
(см. scheduler, который в основном убивает все потоки. Ни одна из этих функций не имеет соответствующей оболочки FFI.
В то время, когда вызывается hs_exit()
, main
из мира Haskell уже закончен. Поскольку ни одна из этих функций не имеет соответствующего эквивалента в модулях GHC.*
, вы не можете вызывать их непосредственно в Haskell и, следовательно, в GHCi, так как нет соответствующей команды :#
.
Итак, в целом, вы не можете. Если бы кто-то добавил команду перезапустить планировщик в GHCi, это было бы просто как пирог. Но, учитывая, что планировщик запускается в hs_init()
и останавливается в hs_exit()
в модели RTS, я сомневаюсь, что это было бы легко расширение.
В зависимости от того, что вы хотите сделать, вы можете обмануть. Вы можете написать свой собственный forkIOMem
, который хранит ThreadId
в глобальном MVar
и заменяет все forkIO
в источниках. Это может быть очень громоздким, особенно если вы работаете с библиотекой, так как вам нужно обеспечить замену forkIO
повсюду.
Вы могли бы, конечно, вмешиваться в пакет base
, но это, вероятно, безумие (все еще возможно), измените forkIO
там и добавьте killAllforkIOs
в Control.Concurrent
. (Я уже говорил, что это, наверное, безумие, правда?)