Mercurial > pub > ImplabNet
diff Implab/Parallels/SharedLock.cs @ 192:f1da3afc3521 release v2.1
Слияние с v2
author | cin |
---|---|
date | Fri, 22 Apr 2016 13:10:34 +0300 |
parents | e9e7940c7d98 |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab/Parallels/SharedLock.cs Fri Apr 22 13:10:34 2016 +0300 @@ -0,0 +1,202 @@ +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(); + // the count of locks currently acquired by clients + int m_locks; + // the count of pending requests for upgrade + int m_upgrades; + bool m_exclusive; + + public bool LockExclusive(int timeout) { + lock (m_lock) { + var dt = timeout; + if (m_locks > m_upgrades) { + var t1 = Environment.TickCount; + do { + if (!Monitor.Wait(m_lock, timeout)) + return false; + + if (m_locks == m_upgrades) + break; + + if (timeout > 0) { + dt = timeout - Environment.TickCount + t1; + if (dt < 0) + return false; + } + } while(true); + } + m_exclusive = true; + m_locks ++; + return true; + } + } + + public void LockExclusive() { + lock (m_lock) { + + while (m_locks > m_upgrades) + Monitor.Wait(m_lock); + + m_exclusive = true; + m_locks ++; + } + } + + /// <summary> + /// Acquires a shared lock. + /// </summary> + /// <returns><c>true</c>, if the shared lock was acquired, <c>false</c> if the specified timeout was expired.</returns> + /// <param name="timeout">Timeout.</param> + public bool LockShared(int timeout) { + lock (m_lock) { + if (!m_exclusive) { + m_locks++; + return true; + } + + if (m_locks == m_upgrades) { + m_exclusive = false; + m_locks = 1; + return true; + } + + var t1 = Environment.TickCount; + var dt = timeout; + do { + if (!Monitor.Wait(m_lock, dt)) + return false; + + if (m_locks == m_upgrades || !m_exclusive) + break; + + if (timeout >= 0) { + dt = timeout - Environment.TickCount + t1; + if (dt < 0) + return false; + } + } while(true); + + m_locks ++; + m_exclusive = false; + return true; + } + } + + /// <summary> + /// Acquires the shared lock. + /// </summary> + public void LockShared() { + lock (m_lock) { + if (!m_exclusive) { + m_locks++; + } else if (m_locks == m_upgrades) { + m_exclusive = false; + m_locks++; + } else { + while (m_exclusive && m_locks > m_upgrades) + Monitor.Wait(m_lock); + + m_locks++; + m_exclusive = false; + } + } + } + + /// <summary> + /// Upgrades the current lock to exclusive level. + /// </summary> + /// <remarks>If the current lock is exclusive already the method does nothing.</remarks> + public void Upgrade() { + lock (m_lock) { + if (!m_exclusive) { + + if (m_locks <= m_upgrades) + throw new InvalidOperationException(); + + if (m_locks - m_upgrades == 1) { + m_exclusive = true; + } else { + m_upgrades++; + + while (m_locks > m_upgrades) + Monitor.Wait(m_lock); + + m_upgrades--; + m_exclusive = true; + } + } + } + } + + /// <summary> + /// Upgrades the current lock to exclusive level. + /// </summary> + /// <param name="timeout">Timeout.</param> + /// <returns><c>true</c> if the current lock was updated, <c>false</c> the specified timeout was expired.</returns> + /// <remarks>If the current lock is exclusive already the method does nothing.</remarks> + public bool Upgrade(int timeout) { + lock (m_lock) { + if (m_exclusive) + return true; + if (m_locks <= m_upgrades) + throw new InvalidOperationException(); + + if (m_locks - m_upgrades == 1) { + m_exclusive = true; + } else { + var t1 = Environment.TickCount; + var dt = timeout; + m_upgrades++; + do { + if (!Monitor.Wait(m_lock, dt)) { + m_upgrades--; + return false; + } + + // we may get there but the shared lock already aquired + if (m_locks == m_upgrades) + break; + + if (timeout >= 0) { + dt = timeout - Environment.TickCount + t1; + if (dt < 0) { + m_upgrades--; + return false; + } + } + } while(true); + m_upgrades--; + m_exclusive = true; + } + return true; + } + } + + /// <summary> + /// Downgrades this lock to shared level. + /// </summary> + public void Downgrade() { + lock (m_lock) + m_exclusive = false; + } + + /// <summary> + /// Releases the current lock. + /// </summary> + public void Release() { + lock (m_lock) + // if no more running threads left + if (--m_locks == m_upgrades) + Monitor.PulseAll(m_lock); + } + } +} +