-- | -- Module: Acme.Missiles -- License: Public domain -- Portability: non-portable -- -- The 'launchMissiles' action, as mentioned in: -- -- * /Beautiful concurrency/, by Simon Peyton Jones, to appear in -- \"Beautiful code\", ed Greg Wilson, O'Reilly 2007. -- module Acme.Missiles ( launchMissiles, -- * Launching missiles in the 'STM' monad withMissilesDo, launchMissilesSTM, ) where import Control.Concurrent import Control.Concurrent.STM import Control.Exception (bracket) import Control.Monad (forever) import System.IO.Unsafe (unsafePerformIO) -- | Cause serious international side effects. launchMissiles :: IO () launchMissiles = putStrLn "Nuclear launch detected." -- | Perform initialization needed to launch missiles in the 'STM' monad. withMissilesDo :: IO a -> IO a withMissilesDo action = bracket (forkIO doLaunching) killThread (\_ -> action) where doLaunching = forever $ do atomically $ do n <- readTVar missileCommand if n > 0 then writeTVar missileCommand (n - 1) else retry launchMissiles -- | Launch missiles within an 'STM' computation. Even if the memory -- transaction is retried, only one salvo of missiles will be launched. -- -- Example: -- -- >import Acme.Missiles -- >import Control.Concurrent -- >import Control.Concurrent.STM -- > -- >main :: IO () -- >main = withMissilesDo $ do -- > xv <- atomically $ newTVar (2 :: Int) -- > yv <- atomically $ newTVar (1 :: Int) -- > atomically $ do -- > x <- readTVar xv -- > y <- readTVar yv -- > if x > y -- > then launchMissilesSTM -- > else return () -- > threadDelay 100000 launchMissilesSTM :: STM () launchMissilesSTM = do n <- readTVar missileCommand writeTVar missileCommand $! n + 1 missileCommand :: TVar Integer {-# NOINLINE missileCommand #-} missileCommand = unsafePerformIO (newTVarIO 0)