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);
+        }
+    }
+}
+