Dynamic event switching results in "*** Exception: thread blocked indefinitely in an MVar operation" deadlock #293
Replies: 11 comments
-
I decided to take a look at the source code of reactive-banana and saw this: Reactive.Banana.Internal.Combinators.compile compile :: Moment () -> IO EventNetwork
compile setup = do
actuated <- newIORef False -- flag to set running status
s <- newEmptyMVar -- setup callback machinery
let
whenFlag flag action = readIORef flag >>= \b -> when b action
runStep f = whenFlag actuated $ do
s1 <- takeMVar s -- read and take lock
-- pollValues <- sequence polls -- poll mutable data
(output, s2) <- f s1 -- calculate new state
putMVar s s2 -- write state
output -- run IO actions afterwards
eventNetwork = EventNetwork
{ runStep = runStep
, actuate = writeIORef actuated True
, pause = writeIORef actuated False
}
(output, s0) <- -- compile initial graph
Prim.compile (runReaderT setup eventNetwork) Prim.emptyNetwork
putMVar s s0 -- set initial state
return $ eventNetwork Could it be that the value of |
Beta Was this translation helpful? Give feedback.
-
I managed to get the code to work by creating the event after it was first converted to a behavior: {-# LANGUAGE RecursiveDo #-}
module Main2 where
import Control.Monad (when)
import qualified Reactive.Banana as B
import qualified Reactive.Banana.Frameworks as BF
data Vars = Vars { var :: Int }
data EventType = Increase | Decrease | Jump
instance Semigroup EventType where a <> _ = a
main :: IO ()
main = do
(addHandler, fire) <- BF.newAddHandler
network <- B.compile $ eventNetworkDescription addHandler
BF.actuate network
loop fire
where
loop fire = do
s <- getLine
case s of
"i" -> fire Increase
"d" -> fire Decrease
_ -> pure ()
when (s /= "x") $ loop fire
eventNetworkDescription :: BF.AddHandler EventType -> BF.MomentIO ()
eventNetworkDescription addHandler = mdo
events <- BF.fromAddHandler addHandler
let vars = Vars 1
stateE <- B.accumE vars $ doSomethingWithState <$> (events <> feedbackEvents)
stateB <- B.stepper vars stateE
futureStateE <- BF.changes stateB
feedbackEvents <- getFeedbackEvents stateB -- <- ❗ feedbackEvents is now created here ❗
BF.reactimate' $ fmap printState <$> futureStateE
doSomethingWithState :: EventType -> (Vars -> Vars)
doSomethingWithState Increase (Vars n) = Vars (n + 1)
doSomethingWithState Decrease (Vars n) = Vars (n - 1)
doSomethingWithState Jump _ = Vars 1000
getFeedbackEvents :: B.Behavior Vars -> BF.MomentIO (B.Event EventType)
getFeedbackEvents b = do
(e, fire) <- BF.newEvent
eb <- BF.changes b
BF.reactimate' $ fmap (fire . varToEvent) <$> eb
pure $ B.filterJust e
where
varToEvent :: Vars -> Maybe EventType
varToEvent (Vars 5) = Just Jump
varToEvent _ = Nothing
printState :: Vars -> IO ()
printState (Vars n) = print n But I still feel like it should work the original way I had it too instead of with this work-around... :/ |
Beta Was this translation helpful? Give feedback.
-
There's definitely something up here, because I'm also getting this in my app. I'm pretty sure the bug happens if you try and fire events in your imageChanged <- switchE =<< execute do
imagePathChanges <&> \newPath -> do
(imageLoaded, onImageLoad) <- newEvent
liftIO do
onImageLoad =<< imdecode ImreadColor <$> BS.readFile newPath
return imageLoaded But if I comment out that middle I note that in your example, |
Beta Was this translation helpful? Give feedback.
-
That might be the issue yes, but still strange that it happens. |
Beta Was this translation helpful? Give feedback.
-
I think this is a duplicate of #190 |
Beta Was this translation helpful? Give feedback.
-
Hello! Yes, this is a duplicate of #190 . Sorry about that — it's a feature, not a bug! Creating a new event handler will reorganize the |
Beta Was this translation helpful? Give feedback.
-
If it is working as intended, is the way I "solved" it the way to go? |
Beta Was this translation helpful? Give feedback.
-
@PiJoKra Uh, could you be more specific about what you want to do? I don't quite understand how It seems that you want some sort of recursion? You do have to be very careful when |
Beta Was this translation helpful? Give feedback.
-
Sorry for my late reply. Yes I am looking for recursion. An event triggering another event. Take for example a video game: an event causes your character to walk to a wall which should cause a collision-event that can be acted upon. What is the best way to handle such a situation? I feel like I am missing something. Edit: I was wondering why I did it the way I did by translating the
Since the answer there already mentions ...
... I am wondering if your stance has changed from "This is a decision that Conal Elliott made in his original FRP semantics and I've decided to stick to it." |
Beta Was this translation helpful? Give feedback.
-
The collision-event will be fine as long as it's not recursive — if you try to make the event that walks the character into the wall depend on the collision, then you may end up with conflicting semantics where the collision only happens if the character walks into a wall, but once a collision happens, the character will not walk into a wall — but this implies that no collision happens. Disallowing recursion of Events forces you to make up your mind on the semantics of this situation. |
Beta Was this translation helpful? Give feedback.
-
(As this discussion does not qualify as an "issue" anymore, i.e. a defect or enhancement, I'm moving it to the Discussion forum.) |
Beta Was this translation helpful? Give feedback.
-
Hello,
While working on an application I noticed that the application hang any moment I created a new event from an event callback.
I decided to create a little application to test if it was my code, my misunderstanding of the framework or a bug.
I think I already ruled out the first option, as I get the exception "*** Exception: thread blocked indefinitely in an MVar operation" when I run the code below in GHCi.
You can enter "i" and "d" to increase or decrease the value in the state, and if the state gets to 5 it jumps to 1000. It is that jump that is causing the problems.
Do you know if I am doing something wrong or if this is a bug? Thanks in advance!
Beta Was this translation helpful? Give feedback.
All reactions