[Haskell] Optimizing locking with MVars

Bulat Ziganshin bulat.ziganshin at gmail.com
Wed May 3 03:26:49 EDT 2006


Hello John,

Wednesday, May 3, 2006, 2:37:03 AM, you wrote:

> This reminds me, I wonder if we should have an MVar varient that is
> _just_ for locking, it would have no separate take and put primitives,
> just a withLock, enforcing the restriction that the thread that took the
> lock is the same one that will return it.

to be exact, i has the following definitions, which uses class to
define 'lock' operation and therefore allow alternative
implementations in future without need to change application code that
uses this operation:

> data WithLocking h = WithLocking h !(MVar ())
> 
> -- | Add lock to object to ensure its proper use in concurrent threads
> addLocking h = do
>     mvar <- newMVar ()
>     return (WithLocking h mvar)
> 
> -- | Run `action` with locked version of object `h`
> withLocking :: h -> (WithLocking h -> IO a) -> IO a
> withLocking h action = do
>     addLocking h >>= action
> 
> -- | Define class of locking implementations, where 'lh' holds lock around 'h'
> class Locking lh h | lh->h where
>     -- | Perform `action` while exclusively locking wrapped object
>     lock :: lh -> (h->IO a) -> IO a
> 
> instance Locking (WithLocking h) h where
>     {-# INLINE lock #-}
>     lock (WithLocking h mvar) action = do
>           -- Faster analog of withMVar
>           Exception.catch (do takeMVar mvar
>                               result <- action h
>                               putMVar mvar ()
>                               return res
>                           )
>                           (\e -> do tryPutMVar mvar (); throw e)
> 
> liftLock1 action h         = lock h (\a -> action a)
> liftLock2 action h x       = lock h (\a -> action a x)
> liftLock3 action h x y     = lock h (\a -> action a x y)
> liftLock4 action h x y z   = lock h (\a -> action a x y z)
> liftLock5 action h x y z t = lock h (\a -> action a x y z t)
> {-# INLINE liftLock1 #-}
> {-# INLINE liftLock2 #-}
> 
> instance (Show h) => Show (WithLocking h) where
>     show (WithLocking h _) = "WithLocking ("++ show h ++")"


and then any type class can be made client of this library, f.e.:

> type WithLocking2 a e m = WithLocking (a e m)
> 
> instance (MArray a e m) => (MArray (WithLocking2 a) e m) where
>     newArray lu e = newArray lu e >>= addLocking
>     newArray_ lu  = newArray_ lu  >>= addLocking
>     unsafeReadArray = liftLock2 unsafeReadArray
>     unsafeWriteArray = liftLock3 unsafeWriteArray
> 
> 
> main = do arr <- newArray (0,9) 0 >>= addLocking
>           readArray arr 0 >>= writeArray arr 1
>           .....



-- 
Best regards,
 Bulat                            mailto:Bulat.Ziganshin at gmail.com



More information about the Haskell mailing list