# HG changeset patch
# User cin
# Date 2015-01-29 15:31:06
# Node ID 471f596b26037cfda5566b4b505fcd2ba38b452d
# Parent 6241bff0cd64e284346ea70c208272528be53d54
Added SharedLock to synchronization routines
diff --git a/Implab/Implab.csproj b/Implab/Implab.csproj
--- a/Implab/Implab.csproj
+++ b/Implab/Implab.csproj
@@ -143,8 +143,6 @@
-
-
@@ -156,6 +154,7 @@
+
diff --git a/Implab/Parallels/AsyncQueue.cs b/Implab/Parallels/AsyncQueue.cs
--- a/Implab/Parallels/AsyncQueue.cs
+++ b/Implab/Parallels/AsyncQueue.cs
@@ -495,11 +495,11 @@ namespace Implab.Parallels {
#region ICollection implementation
public void Add(T item) {
- throw new InvalidOperationException();
+ throw new NotSupportedException();
}
public void Clear() {
- throw new InvalidOperationException();
+ throw new NotSupportedException();
}
public bool Contains(T item) {
@@ -511,7 +511,7 @@ namespace Implab.Parallels {
}
public bool Remove(T item) {
- throw new NotImplementedException();
+ throw new NotSupportedException();
}
public int Count {
diff --git a/Implab/Parallels/MTCustomQueue.cs b/Implab/Parallels/MTCustomQueue.cs
deleted file mode 100644
--- a/Implab/Parallels/MTCustomQueue.cs
+++ /dev/null
@@ -1,135 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Collections;
-
-namespace Implab.Parallels {
- public class MTCustomQueue : IEnumerable where TNode : MTCustomQueueNode {
- TNode m_first;
- TNode m_last;
-
- public void Enqueue(TNode next) {
- Thread.MemoryBarrier();
-
- var last = m_last;
-
- // Interlocaked.CompareExchange implies Thread.MemoryBarrier();
- // to ensure that the next node is completely constructed
- while (last != Interlocked.CompareExchange(ref m_last, next, last))
- last = m_last;
-
- if (last != null)
- last.next = next;
- else
- m_first = next;
- }
-
- public bool TryDequeue(out TNode node) {
- TNode first;
- TNode next;
- node = null;
-
- Thread.MemoryBarrier();
- do {
- first = m_first;
- if (first == null)
- return false;
- next = first.next;
- if (next == null) {
- // this is the last element,
- // then try to update the tail
- if (first != Interlocked.CompareExchange(ref m_last, null, first)) {
- // this is the race condition
- if (m_last == null)
- // the queue is empty
- return false;
- // tail has been changed, we need to restart
- continue;
- }
-
- // tail succesfully updated and first.next will never be changed
- // other readers will fail due to inconsistency m_last != m_fist && m_first.next == null
- // however the parallel writer may update the m_first since the m_last is null
-
- // so we need to fix inconsistency by setting m_first to null or if it has been
- // updated by the writer already then we should just to give up
- Interlocked.CompareExchange(ref m_first, null, first);
- break;
-
- }
- if (first == Interlocked.CompareExchange(ref m_first, next, first))
- // head succesfully updated
- break;
- } while (true);
-
- node = first;
- return true;
- }
-
- #region IEnumerable implementation
-
- class Enumerator : IEnumerator {
- TNode m_current;
- TNode m_first;
-
- public Enumerator(TNode first) {
- m_first = first;
- }
-
- #region IEnumerator implementation
-
- public bool MoveNext() {
- m_current = m_current == null ? m_first : m_current.next;
- return m_current != null;
- }
-
- public void Reset() {
- m_current = null;
- }
-
- object IEnumerator.Current {
- get {
- if (m_current == null)
- throw new InvalidOperationException();
- return m_current;
- }
- }
-
- #endregion
-
- #region IDisposable implementation
-
- public void Dispose() {
- }
-
- #endregion
-
- #region IEnumerator implementation
-
- public TNode Current {
- get {
- if (m_current == null)
- throw new InvalidOperationException();
- return m_current;
- }
- }
-
- #endregion
- }
-
- public IEnumerator GetEnumerator() {
- return new Enumerator(m_first);
- }
-
- #endregion
-
- #region IEnumerable implementation
-
- IEnumerator IEnumerable.GetEnumerator() {
- return GetEnumerator();
- }
-
- #endregion
- }
-}
-
diff --git a/Implab/Parallels/MTCustomQueueNode.cs b/Implab/Parallels/MTCustomQueueNode.cs
deleted file mode 100644
--- a/Implab/Parallels/MTCustomQueueNode.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Implab.Parallels {
- public class MTCustomQueueNode where TNode : MTCustomQueueNode {
- public TNode next;
- }
-}
-
diff --git a/Implab/Parallels/SharedLock.cs b/Implab/Parallels/SharedLock.cs
new file mode 100644
--- /dev/null
+++ b/Implab/Parallels/SharedLock.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Threading;
+using System.Diagnostics;
+
+namespace Implab.Parallels {
+ ///
+ /// Implements a lightweight mechanism to aquire a shared or an exclusive lock.
+ ///
+ 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);
+ }
+ }
+
+ }
+}
+
diff --git a/Implab/Parallels/Signal.cs b/Implab/Parallels/Signal.cs
--- a/Implab/Parallels/Signal.cs
+++ b/Implab/Parallels/Signal.cs
@@ -3,7 +3,7 @@ using System.Threading;
namespace Implab.Parallels {
///
- /// Implements simple signalling logic using .
+ /// Implements a simple signalling logic using .
///
public class Signal {
readonly object m_lock = new object();
diff --git a/Implab/Parallels/WorkerPool.cs b/Implab/Parallels/WorkerPool.cs
--- a/Implab/Parallels/WorkerPool.cs
+++ b/Implab/Parallels/WorkerPool.cs
@@ -7,7 +7,7 @@ namespace Implab.Parallels {
public class WorkerPool : DispatchPool {
AsyncQueue m_queue = new AsyncQueue();
- int m_queueLength = 0;
+ int m_queueLength;
readonly int m_threshold = 1;
public WorkerPool(int minThreads, int maxThreads, int threshold)
@@ -40,7 +40,7 @@ namespace Implab.Parallels {
var lop = TraceContext.Instance.CurrentOperation;
- EnqueueTask(delegate() {
+ EnqueueTask(delegate {
TraceContext.Instance.EnterLogicalOperation(lop, false);
try {
promise.Resolve(task());