Is it safe to trigger the fire action in
(addHandler, fire) <- newAddHandler
from a different thread from which the reactive-banana graph was compiled?
Yes, this is safe, but there is the caveat that @Cirdec mentioned.
For conreteness, consider the following example that creates an event network using the addHandler
in a separate thread and then calls fire
repeatedly in the main thread
import Control.Concurrent (myThreadId, threadDelay, forkIO)
main = do
...
(addHandler, fire) <- newAddHandler
let networkDescription :: MomentIO ()
networkDescription = do
e <- fromAddHandler addHandler
...
reactimate $ (print =<< myThreadId) <$ e -- reactimate
forkIO $ do
network <- compile networkDescription
actuate network
...
forever $ do -- event loop
threadDelay (10^6)
fire ()
(See the documentation "Terminating the program" in Control.Concurrent for why I've put the event loop in the main thread as opposed to putting the network in the main thread.)
In this and similar situations, the following will hold:
reactimate
will be run in the thread that calls fire
, not in the thread where the network was compiled. This is what @Cirdec already mentioned.fire
, then it could potentially interleave with other calls to fire
, i.e. the program could be calling fire
twice concurrently. Then,
Time -> a
and lists [(Time,a)]
as usual.reactimate
s may interleave. In other words, the pure FRP part will stay pure, but the actual IO is subject to concurrency as usual.