Home > Back-end >  Can I use IORef as a kind of "mutex" in this way?
Can I use IORef as a kind of "mutex" in this way?

Time:09-12

I have an operation that must be executed in the mutual exclusive way. In other languages I can do something like (Python like pseudocode):

with myLock:
  # here lock is acquired
  do mutual exclusive operation
# here lock is released

Sure, I can do it in Haskell with MVar: to take it and then to put it back. But I want to do it with IORef as:

-- somewhere
duringOperation :: IORef Bool

.....

-- operation execution:

    mayIStart <- atomicModifyIORef' duringOperation $ \case
      -- tuple is treated as (lock/keep-locked, may I start the operation)
      True  -> (True, False)
      False -> (True, True)
    if mayIStart then do
      -- here I am doing my operation in a mutual exclusive way
      ...
      -- after completion I reset duringOperation flag
      atomicWriteIORef' _duringOperation False
    else
      -- something else...

It looks like typical "atomic" or "synchronized" flag in other languages. But I am not sure how it's safe in Haskell and with an usage of IORef for such goal. Again, my idea is to do it with IORef. Is it really safe (the operation will be really mutual exclusive)?

CodePudding user response:

Yes, it's safe. That is precisely what the atomic in atomicModifyIORef means. From the Fine Documentation:

Atomically modifies the contents of an IORef.

This function is useful for using IORef in a safe way in a multithreaded program. If you only have one IORef, then using atomicModifyIORef to access and modify it will prevent race conditions.

I believe you do not need to write atomically when releasing the "mutex", i.e. writeIORef duringOperation False should be fine -- believing that the operation is running when it isn't is safe, just less efficient.

  • Related