view Implab/Parallels/SharedLock.cs @ 129:471f596b2603 v2

Added SharedLock to synchronization routines
author cin
date Thu, 29 Jan 2015 18:31:06 +0300
parents
children 671f60cd0250
line wrap: on
line source

using System;
using System.Threading;
using System.Diagnostics;

namespace Implab.Parallels {
    /// <summary>
    /// Implements a lightweight mechanism to aquire a shared or an exclusive lock.
    /// </summary>
    public class SharedLock {
        readonly object m_lock = new object();
        int m_locks;
        bool m_exclusive;

        public bool LockExclusive(int timeout) {
            lock (m_lock) {
                if (m_locks > 0 && !Monitor.Wait(m_lock, timeout))
                    return false;
                m_exclusive = true;
                m_locks = 1;
            }
        }

        public void LockExclusive() {
            LockExclusive(-1);
        }

        public bool LockShared(int timeout) {
            lock (m_lock) {
                if (!m_exclusive) {
                    m_locks++;
                    return true;
                }

                if (m_lock == 0) {
                    m_exclusive = false;
                    m_locks = 1;
                    return true;
                }
                
                if (Monitor.Wait(m_lock, timeout)) {
                    Debug.Assert(m_locks == 0);
                    m_locks = 1;
                    m_exclusive = false;
                    return true;
                }
                return false;
            }
        }

        public void LockShared() {
            LockShared(-1);
        }

        public void ReleaseShared() {
            lock (m_lock) {
                if (m_exclusive || m_locks <= 0)
                    throw new InvalidOperationException();
                m_locks--;
                if (m_locks == 0)
                    Monitor.PulseAll(m_lock);
            }
        }

        public void ReleaseExclusive() {
            lock (m_lock) {
                if (!m_exclusive && m_locks != 1)
                    throw new InvalidOperationException();
                m_locks = 0;
                Monitor.PulseAll(m_lock);
            }
        }

    }
}