What I'd like to do is something like this where every time one of these print
actions occurs it updates the counter to ensure that the next subsequent occurrence of a print action will always have the correct order in which it occurred among any of the possible print
actions that may occur across multiple threads shown by the counter. The problem in my example is that if the IORef
is read at the same time between threads then two or more print
actions will have the same counter value. From what I've read it seems that using the Data.Atomics.Counter library would solve this problem but i am having a really hard time understanding how to use it do so. Can anyone show me an example or try to explain it to me please?
main = do
myref <- newIORef 1 :: IO (IORef Int)
void(forkIO (forever $ do ref <- readIORef myref
print ("hi " show (ref))
modifyIORef myref ( 1) ))
void(forkIO (forever $ do ref <- readIORef myref
print ("hey " show (ref))
modifyIORef myref ( 1) ))
forever $ do ref <- readIORef myref
print ("hello " show (ref))
modifyIORef myref ( 1)
CodePudding user response:
I would use an MVar
for this.
inc mvar = forever $ do
v <- takeMVar mvar
print v
putMVar mvar (v 1)
main = do
mvar <- newMVar 1
forkIO (inc mvar)
forkIO (inc mvar)
inc mvar
It is important that the print
occur between takeMVar
and putMVar
, while the MVar
is empty; otherwise another thread may empty the MVar
and execute its print
.
CodePudding user response:
You could use atomicModifyIORef'
. It would look something like:
increment ref = forever do
val <- atomicModifyIORef' ref \old -> (old 1, old)
print val
main = do
ref <- newIORef 0
forkIO $ increment ref
forkIO $ increment ref
increment ref