Wed, 12 Apr 2000 23:28:53 +0100, Claus Reinke <[EMAIL PROTECTED]> pisze:

[...]

It becomes hard to follow for me. Anyway, that's how I've implemented
a mutex with tryLock, i.e. MVar () with tryTakeMVar; for MVar a replace
Maybe with Either a and Bool with Maybe a:


newtype Mutex = Mutex (MVar (Maybe [MVar ()]))
-- Nothing    - unlocked
-- Just queue - locked
-- MVar is empty only temporarily, for atomicity of operations.

newMutex:: IO Mutex
newMutex = liftM Mutex (newMVar Nothing)

lock:: Mutex -> IO ()
lock (Mutex m) = do
    locked <- takeMVar m
    case locked of
        Nothing    -> putMVar m (Just [])
        Just queue -> do
            me <- newEmptyMVar
            putMVar m (Just (queue++[me]))
            takeMVar me -- Wait.

unlock:: Mutex -> IO ()
unlock (Mutex m) = do
    Just queue <- takeMVar m -- Error when already unlocked.
    case queue of
        []   -> putMVar m Nothing
        t:ts -> putMVar t () >> putMVar m (Just ts)
    
tryLock:: Mutex -> IO Bool
tryLock (Mutex m) = do
    locked <- takeMVar m
    case locked of
        Nothing -> putMVar m (Just []) >> return True
        Just _  -> putMVar m locked    >> return False


There should be rarely the need of checking whether an MVar is empty,
because the answer will not be accurate. But tryTakeMVar is safe,
useful, and does not need a change in MVar's internals.

-- 
 __("<    Marcin Kowalczyk * [EMAIL PROTECTED] http://qrczak.ids.net.pl/
 \__/              GCS/M d- s+:-- a23 C+++$ UL++>++++$ P+++ L++>++++$ E-
  ^^                  W++ N+++ o? K? w(---) O? M- V? PS-- PE++ Y? PGP+ t
QRCZAK                  5? X- R tv-- b+>++ DI D- G+ e>++++ h! r--%>++ y-


Reply via email to