2015-09-16 9 views

risposta

4

Sì, questo è sicuro, ma c'è l'avvertenza che @Cirdec ha menzionato.

Per conreteness, si consideri il seguente esempio che crea una rete di eventi mediante la addHandler in un thread separato e quindi chiama fire più volte nel thread principale

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() 

(Vedere la documentazione "Terminating the program" in Control.Concurrent per il motivo per cui ho messo . il ciclo degli eventi nel thread principale in contrasto con la realizzazione della rete nel thread principale)

in questa e simili situazioni, il seguente conterrà:

  • Le azioni IO eseguite da reactimate verranno eseguite nella thread che chiama fire, non nel thread in cui è stata compilata la rete. Questo è ciò che @Cirdec ha già menzionato.
  • Se esistesse un secondo thread che chiamasse anche fire, potrebbe potenzialmente intercalarsi con altre chiamate a fire, ad esempio il programma potrebbe chiamare lo fire due volte contemporaneamente. Quindi,
    • Reactive-banana utilizza un blocco per garantire che Behaviors ed Eventi vengano aggiornati in modo coerente. È possibile trattarli come funzioni pure Time -> a e liste [(Time,a)] come al solito.
    • Tuttavia, le azioni IO provenienti da reactimate s possono essere interlacciate. In altre parole, la parte FRP pura rimarrà pura, ma l'IO effettivo è soggetto alla concorrenza come al solito.
+0

Ciò rende molto chiaro. –

3

L'esecuzione del gestore fire è sicura; legge uno IORef che viene aggiornato atomicamente e esegue ciascuno dei gestori aggiunti nel thread corrente. Indipendentemente dal fatto che sia sicuro dipenderà da quali gestori sono stati aggiunti allo addHandler.

L'utilizzo di addHandler in interpretAsHandler, fromAddHandler o fromChanges deve essere sicuro. Nulla di ciò che conosco in banana reattiva ha alcuna affinità con i thread, e anche se fosse così, questi sono i motivi per cui è stato creato newAddHandler, quindi dovrebbe essere comunque sicuro.

Quello che devi fare attenzione è le azioni IO() eseguite da reactimate. Se è necessario riattivare le azioni IO che devono essere eseguite in un thread specifico (per OpenGL output, ecc.), È necessario produrre solo azioni IO() che invieranno i loro dati a quel thread. In questo complete OpenGL example for reactive-banana le azioni IO() per l'output OpenGL, che hanno affinità di thread, vengono eseguite nel thread OpenGL. Invece di reactimate ing del Event (IO()) eseguirli direttamente sono aggiunti a un 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 

Il IORef un'azienda IO() azioni da eseguire è leggere e ciascuna di tutte le azioni vengono eseguite in un contesto che so è in OpenGL filo.

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)