
Hello Is it possible to implement an operation like tryReadMVar :: MVar a -> IO (Maybe a) in a good fashion? The semantics should be "Read the value of the MVar without taking it if it is filled, otherwise return Nothing". There are several easy and flawed implementations: tryReadMvar mv = do e <- isEmptyMVar mv case e of True -> return Nothing False-> readMVar mv >>= return . Just This does not work because there can be a thread switch between the isEmpty and readMVar. tryReadMVar mv = do mc <- tryTakeMVar mv case mc of Nothing -> return mc Just v -> putMVar mv v >> return mc Now this can block on the putMVar if there was a thread switch and someone filled the MVar behind our back. Using tryPutMVar does not help much as it just creates another race condition: tryReadMVar mv = do mc <- tryTakeMVar mv case mc of Nothing -> return mc Just c -> tryPutMVar mv v >> return mc Consider what happens if the tryPutMVar fails: -- read till we get the value with foobar in the middle loopTill mv = do foobar mc <- tryReadMVar mv case mc of Nothing -> loopTill mv Just v -> return v maybe (loopTill mv) process (tryReadMVar mv) error = do mv <- newEmptyMVar forkIO (mapM_ (\i -> putMVar mv i) [1..10]) mapM_ (\_ -> loopTill mv >>= print >> takeMVar mv >>= print) [1..10] If a tryPutMVar fails, then there will be less than ten values to read which will make the process block in takeMVar. This seems quite straightforward in C with GHC (might be wrong in the SMP case with locking?): tryReadMVarzh_fast { W_ mvar, info; /* args: R1 = MVar closure */ mvar = R1; info = GET_INFO(mvar); if (info == stg_EMPTY_MVAR_info) RET_NP(0, stg_NO_FINALIZER_closure); RET_NP(1, vStgMVar_value(mvar); } What is the best way to do this? - Einar Karttunen