在reactive-banana中,从多个线程触发处理程序操作是否安全?



中触发消防动作安全吗?
(addHandler, fire) <- newAddHandler

从另一个线程编译反应-香蕉图?

是的,这是安全的,但是有@Cirdec提到的警告。

为了更具体,考虑下面的例子,在一个单独的线程中使用addHandler创建一个事件网络,然后在主线程

中重复调用fire
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 ()

(参见控制中的"终止程序"文档)。并发,这就是为什么我把事件循环放在主线程中,而不是把网络放在主线程中。

在这种和类似的情况下,以下语句成立:

  • reactimate执行的IO动作将在调用fire的线程中运行,而不是在编译网络的线程中。这是@Cirdec已经提到的。
  • 如果有第二个线程也调用fire,那么它可能会与其他对fire的调用交错,即程序可能并发地调用fire两次。然后,
    • Reactive-banana使用锁来确保行为和事件被一致地更新。您可以将它们视为纯函数Time -> a,并像往常一样列出[(Time,a)]。然而,来自reactimate的IO操作可能会交错。换句话说,纯粹的FRP部分将保持纯粹,但实际的IO将像往常一样受到并发性的影响。

触发fire处理程序本身是安全的;它读取正在自动更新的IORef,并在当前线程中运行每个添加的处理程序。这是否安全取决于addHandler中添加了哪些处理程序。

interpretAsHandlerfromAddHandlerfromChanges中使用addHandler应该是安全的。我所知道的react -banana中没有任何线程亲和性,即使有,这也是newAddHandler的目的,所以无论如何它应该是安全的。

需要注意的是reactimate执行的IO ()动作。如果你需要重新计算需要在特定线程中运行的IO动作(对于OpenGL输出等),你只需要生成将其数据发送到该线程的IO ()动作。在这个完整的OpenGL react -banana示例中,具有线程亲和性的OpenGL输出的IO ()动作在OpenGL线程中运行。与reactimate直接执行Event (IO ())不同,它们被添加到IORef

whenIdleRef <- newIORef (return ())
let
    addWhenIdle :: IO () -> IO ()
    addWhenIdle y = atomicModifyIORef' whenIdleRef (x -> (x >> y, ()))
    runWhenIdle :: IO ()
    runWhenIdle = atomicModifyIORef' whenIdleRef (x -> (return (), x)) >>= id
let networkDescription  :: forall t. Frameworks t => Moment t ()
    networkDescription  = do
        reactimate $ fmap addWhenIdle (whenIdle outputs)
                     ^                ^
                     |                Event (IO ())
                     Stuff the event into an IORef

IORef持有IO ()动作运行被读取,所有的动作都在一个上下文中运行,我知道是在OpenGL线程。

idleCallback $= Just (do           -- will be executed in the OpenGL thread when it's idle
    getCurrentTime >>= raiseTime
    runWhenIdle                    -- run those `IO ()` actions in this thread
    postRedisplay Nothing)

相关内容

最新更新