module Main where
import Control.Concurrent (forkIO, threadDelay)
import Control.Monad (forM_, when)
import Data.IORef (newIORef, readIORef, writeIORef)
import System.IO
import System.Mem (performGC)
import System.Process (createPipe)
main :: IO ()
main = do
(readH, writeH) <- createPipe
putStrLn $ "opened pipe read=" <> show readH <> " write=" <> show writeH
-- Hand readH to a thread that does nothing but die after 500ms.
-- Once the thread exits, readH is unreachable and eligible for GC.
closeThread <- newIORef False
let
go = do
threadDelay 100_000
shouldClose <- readIORef closeThread
if shouldClose
then putStrLn $ "reader thread exiting (dropping " <> show readH <> ")"
else go
_ <- forkIO go
-- If the `readH` isn't explicitly kept alive for the duration of `forM_`,
-- it'll cause a failure when reading `writeH`.
forM_ [1 :: Int .. 10] $ \i -> do
_ <- hPutStr writeH ("tick " <> show i) >> hFlush writeH
putStrLn $ "write #" <> show i <> " ok"
-- After some time, close the read thread so it gets GC'd
when (i == 2) $ do
_ <- writeIORef closeThread True
putStrLn $ "shutting down read thread"
pure ()
threadDelay 100_000
performGC
putStrLn "write done"