Multithreading &引用;STM事务中无限期阻塞的线程;在线程从未被阻塞的情况下

Multithreading &引用;STM事务中无限期阻塞的线程;在线程从未被阻塞的情况下,multithreading,haskell,asynchronous,race-condition,stm,Multithreading,Haskell,Asynchronous,Race Condition,Stm,在我的程序中,我将async库与stm结合使用 主线程分叉两个线程,直到其中一个(可能是其中一个)遇到解决方案为止。该解决方案通过TMVar返回。它们都不会等待任何TMVar,除非在找到解决方案时调用putTMVar,其中一个保证永远运行,除非被杀死。那么,如果至少有一个子线程在存储结果之前不执行任何阻塞STM事务(或死亡),那么我怎么可能“在STM事务中无限期地阻塞线程”(这似乎大约每二十次发生一次) 请注意,两个子线程使用TVars相互通信,但不使用TMVars 简化代码: main ::

在我的程序中,我将
async
库与
stm
结合使用

主线程分叉两个线程,直到其中一个(可能是其中一个)遇到解决方案为止。该解决方案通过TMVar返回。它们都不会等待任何
TMVar
,除非在找到解决方案时调用
putTMVar
,其中一个保证永远运行,除非被杀死。那么,如果至少有一个子线程在存储结果之前不执行任何阻塞STM事务(或死亡),那么我怎么可能“在STM事务中无限期地阻塞线程”(这似乎大约每二十次发生一次)

请注意,两个子线程使用
TVar
s相互通信,但不使用
TMVar
s

简化代码:

main :: IO ()
main = do
  output <- newEmptyTMVar
  result <- withAsync (child1 output) $ \_ -> withAsync (child2 output) $ \_ ->
    let go = do
          result <- atomically $ takeTMVar output
          if someCondition result
            then return result
            else go
    in  go
  print result

child1 :: TMVar Result -> IO ()
child1 output = go 0
  where
    go i = do
      case computation1 i of
        Nothing -> return ()
        Just x -> atomically $ putTMVar x
      go (i + 1)

child2 :: TMVar Result -> IO ()
-- Does some other stuff, but also only interacts with its argument to
-- give back a result, same as child1.
main::IO()
main=do
输出
放手
结果IO()
child1输出=go 0
哪里
去做
案例一
无->返回()
只需x->atomically$putTMVar x
go(i+1)
child2::TMVar结果->IO()
--做一些其他的事情,但也只与它的论点相互作用
--返回一个结果,与child1相同。

为什么您认为这是不可能的?考虑操作顺序:<代码>子1>代码>写入TMVAR,<代码>主< /代码>从TMVAR,<代码> Health1 >写入TMVAR(再次满),STM事务中的
child1
child2
块试图
putTMVar
main
此时没有对
output
的实时引用。两个子线程,因此在STM事务中被阻塞。@ThomasM.DuBuisson我认为OP预期
withAsync
将最终杀死(取消)这些线程,因此这里没有真正的死锁。然而,RTS没有考虑“线程终止”,并触发了一个可以说是虚假的“死锁”异常。我不是说RTS的检测策略是错误的,但在这里它处理异步。我在过去遇到过类似的问题,这确实是预期的RTS行为。相关链接:@chi有意义。即使在最好的情况下,这似乎也是一场比赛。在终止子线程或RTS确认没有
输出的读取器
和为所有被阻止的子线程抛出异常之间,赢的是什么。如果在
main
的分支中有超过
takeTMVar
,这一点尤其现实。正确的方法是什么?