Reputation: 1195
I have a function that I fork off into a thread using forkIO. The function runs in a ReaderT monad transformer so that I can pass in a read-only configuration record:
main :: IO ()
main = do
...
forkIO $ runReaderT watcher config
The watcher
function watches an MVar using tryTakeMVar (I don't want it to block.) The MVar is stored in the config and is called "drawer" because it behaves like a transaction drawer between main
and the thread that watcher
is watching in, basically a skip channel.
printThing
has a signature of printThing :: Thing -> ReaderT Config IO ()
and calls putStrLn
to print a Thing
.
watcher :: ReaderT Config IO ()
watcher = do
cfg <- ask
mNewThing <- liftIO $ tryTakeMVar $ drawer cfg
case mNewThing of
Nothing -> do
--liftIO $ putStr "" -- uncommenting this helps
watcher
Just newThing -> do
printThing newThing
watcher
The problem is that the program hangs when it runs. It seems to be stuck in a loop. Calling putStr ""
in main
doesn't help, HOWEVER, calling putStr ""
inside watcher
does trigger the thread -- it starts spinning and printing out Thing
s as expected.
All I can figure is that I'm getting bitten by laziness, but I'm not sure where. I've tried using $!
where possible.
I do IO actions in certain conditions of watcher
, but not all of them. Is that the problem? I need to do IO actions in ALL conditions branches?
If it helps, I didn't have this problem before I wrapped everything up in the ReaderT
transformer. I was just passing config
around as an argument.
Upvotes: 0
Views: 137
Reputation: 152682
Despite the text in your question, I recommend that you let watcher
block. It is quite rare indeed to need non-blocking operations on MVar
s; usually wanting it is a sign you haven't quite internalized the "fork everything" mentality. So:
watcher :: ReaderT Config IO ()
watcher = do
cfg <- ask
newThing <- liftIO . takeMVar $ drawer cfg
printThing newThing
watcher
We can separately address a question of the form "How do I achieve effect X, that seems to me to need non-blocking operations, while only using blocking operations?" if you will write up a separate question with some details about effect X.
Side note: I'd be tempted to write the above in the following way, which has the same meaning but appeals to me more aesthetically:
watcher = forever (asks drawer >>= liftIO . takeMVar >>= printThing)
Upvotes: 3