##// END OF EJS Templates
Added 'Fail' method to RunnableComponent which allows component to move from...
Added 'Fail' method to RunnableComponent which allows component to move from Running to Failed state. Added PollingComponent a timer based runnable component More tests Added FailPromise a thin class to wrap exceptions Fixed error handling in SuccessPromise classes.

File last commit:

r98:4c945d94b9ab v2
r203:4d9830a9bbb8 v2
Show More
MTQueue.cs
143 lines | 4.2 KiB | text/x-csharp | CSharpLexer
using System.Threading;
using System.Collections.Generic;
using System;
using System.Collections;
namespace Implab.Parallels {
public class MTQueue<T> : IEnumerable<T> {
class Node {
public Node(T value) {
this.value = value;
}
public readonly T value;
public Node next;
}
Node m_first;
Node m_last;
public void Enqueue(T value) {
Thread.MemoryBarrier();
var last = m_last;
var next = new Node(value);
// 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 T value) {
Node first;
Node next;
value = default(T);
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);
value = first.value;
return true;
}
#region IEnumerable implementation
class Enumerator : IEnumerator<T> {
Node m_current;
Node m_first;
public Enumerator(Node 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.value;
}
}
#endregion
#region IDisposable implementation
public void Dispose() {
}
#endregion
#region IEnumerator implementation
public T Current {
get {
if (m_current == null)
throw new InvalidOperationException();
return m_current.value;
}
}
#endregion
}
public IEnumerator<T> GetEnumerator() {
return new Enumerator(m_first);
}
#endregion
#region IEnumerable implementation
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
#endregion
}
}