在 reactive-banana 中,从多个线程触发处理程序操作是否安全?
In reactive-banana, is it safe to trigger handler actions from multiple threads?
在
触发开火动作安全吗
(addHandler, fire) <- newAddHandler
来自编译响应香蕉图的不同线程?
触发 fire
处理程序本身是安全的;它读取一个正在自动更新的 IORef
和 运行 当前线程中每个添加的处理程序。这是否安全将取决于向 addHandler
.
添加了哪些处理程序
使用 interpretAsHandler
、fromAddHandler
或 fromChanges
中的 addHandler
应该是安全的。我所知道的 reactive-banana 中没有任何线程亲和力,即使有,这些也是 newAddHandler
的目的,所以无论如何它应该是安全的。
需要注意的是reactimate
执行的IO ()
个动作。如果您需要在特定线程中重新激活 IO
需要 运行 的动作(对于 OpenGL 输出等),您只需要生成 IO ()
将数据发送到该线程的动作线。在此 complete OpenGL example for reactive-banana 中,具有线程关联的 OpenGL 输出的 IO ()
操作在 OpenGL 线程中是 运行。而不是 reactimate
ing 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)
是的,这是安全的,但是@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 ()
(请参阅文档 "Terminating the program" in Control.Concurrent 了解为什么我将事件循环放在主线程中而不是将网络放在主线程中。)
在这种情况和类似情况下,以下内容将成立:
reactimate
执行的IO动作会运行在调用fire
的线程中,不会在调用的线程中网络编译。这是@Cirdec 已经提到的。
- 如果有第二个线程也调用
fire
,那么它可能会与其他对 fire
的调用交错,即程序可能会同时调用 fire
两次。然后,
- Reactive-banana 使用锁来确保行为和事件持续更新。您可以将它们视为纯函数
Time -> a
并照常列出 [(Time,a)]
。
- 但是,来自
reactimate
的 IO 操作可能会交错。换句话说,纯FRP部分将保持纯,但实际IO照常进行并发。
在
触发开火动作安全吗(addHandler, fire) <- newAddHandler
来自编译响应香蕉图的不同线程?
触发 fire
处理程序本身是安全的;它读取一个正在自动更新的 IORef
和 运行 当前线程中每个添加的处理程序。这是否安全将取决于向 addHandler
.
使用 interpretAsHandler
、fromAddHandler
或 fromChanges
中的 addHandler
应该是安全的。我所知道的 reactive-banana 中没有任何线程亲和力,即使有,这些也是 newAddHandler
的目的,所以无论如何它应该是安全的。
需要注意的是reactimate
执行的IO ()
个动作。如果您需要在特定线程中重新激活 IO
需要 运行 的动作(对于 OpenGL 输出等),您只需要生成 IO ()
将数据发送到该线程的动作线。在此 complete OpenGL example for reactive-banana 中,具有线程关联的 OpenGL 输出的 IO ()
操作在 OpenGL 线程中是 运行。而不是 reactimate
ing 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)
是的,这是安全的,但是@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 ()
(请参阅文档 "Terminating the program" in Control.Concurrent 了解为什么我将事件循环放在主线程中而不是将网络放在主线程中。)
在这种情况和类似情况下,以下内容将成立:
reactimate
执行的IO动作会运行在调用fire
的线程中,不会在调用的线程中网络编译。这是@Cirdec 已经提到的。- 如果有第二个线程也调用
fire
,那么它可能会与其他对fire
的调用交错,即程序可能会同时调用fire
两次。然后,- Reactive-banana 使用锁来确保行为和事件持续更新。您可以将它们视为纯函数
Time -> a
并照常列出[(Time,a)]
。 - 但是,来自
reactimate
的 IO 操作可能会交错。换句话说,纯FRP部分将保持纯,但实际IO照常进行并发。
- Reactive-banana 使用锁来确保行为和事件持续更新。您可以将它们视为纯函数