view Implab/Parallels/SharedLock.cs @ 134:04d4c92d0f28 v2

Improved logging
author cin
date Wed, 11 Feb 2015 02:12:15 +0300
parents 671f60cd0250
children e9e7940c7d98
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;
                return true;
            }
        }

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

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

                if (m_locks == 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);
            }
        }

    }
}