Haskell:无限期地在STM事务中被阻塞的线程 [英] Haskell: thread blocked indefinitely in an STM transaction

查看:205
本文介绍了Haskell:无限期地在STM事务中被阻塞的线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有什么方法可以增加时间间隔,在此基础上RTS决定线程在STM事务中无限期阻塞?
这里是我的代码:

pre $ import $ Control $ Concurrent (MVar,newMVar,withMVar)
导入Control.Concurrent.STM
导入合格的Control.Concurrent.ThreadManager作为TM

数据ThreadManager = ThreadManager {tmCounter :: TVar Int,tmTM :: MVar TM.ThreadManager}

data Settings = Settings {
maxThreadsCount :: Int}

createThreadManager :: Settings - > IO线程管理器
createThreadManager s = $ $ b $计数器< - 原子地$ newTVar(maxThreadsCount s)
tm< - TM.make>> = newMVar
return $ ThreadManager counter tm

forkManaged :: ThreadManager - > IO() - > IO ThreadId
forkManaged tm fn = do
原子地$ do
计数器< - readTVar $ tmCounter tm
检查$ counter> 0
writeTVar(tmCounter tm)(counter-1)
withMVar(tmTM tm)$ \thrdmgr - > TM.fork thrdmgr $ do
fn
原子地$ do
计数器< - readTVar $ tmCounter tm
writeTVar(tmCounter tm)(counter + 1)

forkManaged 可确保同时运行的托管线程数量不超过 maxThreadsCount 。它工作正常,直到重负荷。在重负载下RTS引发异常。我认为,在重负荷的情况下,在资源的硬同时竞争中,一些线程没有时间访问STM上下文。所以我认为,增加RTS决定抛出这个异常的时间间隔可能会解决这个问题。

解决方案

Daniel Wagner是对的。这个决定不是由超时决定的。 rts中的相关代码位于 时间表.c



有关异常的地方,请参阅 resurrectThreads 函数抛出。该评论描述了这仅仅是在GC之后被发现为垃圾的线程引发的。 ezyang描述了它如何为mvars工作: http://blog.ezyang.com/2011/07/ blockedindefinitelyonmvar /



[关于检查的错误猜测在我检查其来源并意识到它是只是一个简单的警卫/重试,而不是早期论文中描述的 - 哎呀!我现在怀疑Daniel Wagner在这里也是正确的,这个问题在某种程度上不会增加​​计数器。]


Is there any way to increase a time interval, on the basis of which the RTS decides that thread has blocked indefinitely in an STM transaction? Here is my code:

import Control.Concurrent (ThreadId)
import Control.Concurrent.MVar (MVar,newMVar,withMVar)
import Control.Concurrent.STM
import qualified Control.Concurrent.ThreadManager as TM

data ThreadManager = ThreadManager { tmCounter::TVar Int, tmTM::MVar TM.ThreadManager }

data Settings = Settings {
    maxThreadsCount::Int }

createThreadManager :: Settings -> IO ThreadManager
createThreadManager s = do
    counter <- atomically $ newTVar (maxThreadsCount s)
    tm <- TM.make >>= newMVar
    return $ ThreadManager counter tm

forkManaged :: ThreadManager -> IO () -> IO ThreadId
forkManaged tm fn = do
    atomically $ do
        counter <- readTVar $ tmCounter tm
        check $ counter > 0
        writeTVar (tmCounter tm) (counter - 1)
    withMVar (tmTM tm) $ \thrdmgr -> TM.fork thrdmgr $ do
        fn
        atomically $ do
            counter <- readTVar $ tmCounter tm
            writeTVar (tmCounter tm) (counter + 1)

forkManaged makes sure that amount of simultaneously running managed threads does not exceed maxThreadsCount. It works fine until heavy load. Under heavy load RTS throws an exception. I think under heavy load, on hard concurrent competition for resources, some of threads just have no time to get access to the STM context. So I think, increasing time interval when RTS decides to throw this exception may solve the problem.

解决方案

Daniel Wagner is right. The decision is not made with timeouts. The relevant code in the rts is in Schedule.c

See the resurrectThreads function for where the exception is thrown. The comment describes that this is only thrown to threads found to be garbage after GC. ezyang described how this worked for mvars: http://blog.ezyang.com/2011/07/blockedindefinitelyonmvar/

[bad speculation concerning check removed when I checked its source and realized that it was just a simple guard/retry and not what was described in an earlier paper -- oops! I now suspect that Daniel Wagner is correct here as well, and the issue is somehow that the counter isn't being incremented.]

这篇关于Haskell:无限期地在STM事务中被阻塞的线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆