using System; using System.Threading; public class CyclicBuffer<T> where T : class { private static readonly bool s_multiProcsessors = Environment.ProcessorCount > 1;
private volatile int m_head; private int m_reserve; private int m_tail; private readonly T[] m_buffer;
CyclicBuffer(int capacity) { m_buffer = new T[capacity + 1]; }
public bool Enqueue(T value) { int current; int next; do { Thread.MemoryBarrier(); current = m_reserve; next = NextIndex(current); if (next == m_tail) return false; } while (Interlocked.CompareExchange(ref m_reserve, next, current) != current); while (m_head != current || m_buffer[next] != null) Wait(); m_buffer[next] = value; m_head = next; return true; }
続き public T Dequeue() { int current; int next; do { Thread.MemoryBarrier(); current = m_tail; if (current == m_reserve) return null; next = NextIndex(current); } while (Interlocked.CompareExchange(ref m_tail, next, current) != current); while (m_head < current) Wait(); T value = m_buffer[current]; m_buffer[current] = null; Thread.MemoryBarrier(); return value; }
public bool Enqueue(T value) { int current; int next; do { Thread.MemoryBarrier(); current = m_reserve; next = NextIndex(current); if (next == m_tail) return false; } while (Interlocked.CompareExchange(ref m_reserve, next, current) != current); while (m_head != current || m_buffer[current] != null) Wait(); m_buffer[current] = value; m_head = next; return true; }
ちょっとおおぼけかましてたので再度 using System; using System.Threading;
public class CyclicBuffer<T> where T : class { private static readonly bool s_multiProcsessors = Environment.ProcessorCount > 1;
private int m_head; private int m_tail; private readonly T[] m_buffer;
public CyclicBuffer(int capacity) { m_buffer = new T[capacity + 1]; }
public bool Enqueue(T value) { int current; int next; do { Thread.MemoryBarrier(); current = m_head; next = NextIndex(current); if (next == m_tail) return false; } while (Interlocked.CompareExchange(ref m_head, next, current) != current); while (m_buffer[current] != null) Wait(); m_buffer[current] = value; return true; }
続き public T Dequeue() { int current; int next; do { Thread.MemoryBarrier(); current = m_tail; if (current == m_head) return null; next = NextIndex(current); } while (Interlocked.CompareExchange(ref m_tail, next, current) != current); T value; while ((value = m_buffer[current]) == null) Wait(); m_buffer[current] = null; Thread.MemoryBarrier(); return value; }
public class CyclicBuffer<T> where T : class { private volatile int m_head; private volatile int m_tail; private volatile T[] m_buffer;
public CyclicBuffer(int capacity) { m_buffer = new T[capacity + 1]; }
public bool Enqueue(T value) { if (value == null) throw new ArgumentNullException("value"); int current; int next; do { current = m_head; next = current + 1 == m_buffer.Length ? 0 : current + 1; if (next == m_tail || m_buffer[current] != null) return false; } while (Interlocked.CompareExchange(ref m_head, next, current) != current); m_buffer[current] = value; return true; }
public T Dequeue() { int current; int next; do { current = m_tail; if (current == m_head || m_buffer[current] == null) return null; next = current + 1 == m_buffer.Length ? 0 : current + 1; } while (Interlocked.CompareExchange(ref m_tail, next, current) != current); T value = m_buffer[current]; m_buffer[current] = null; return value; } }
今度こそ最後、汎用化バージョン(structでもOK) using System; using System.Threading;
public class CyclicBuffer<T> { private volatile int m_head; private volatile int m_tail; private readonly Entry[] m_buffer;
public CyclicBuffer(int capacity) { m_buffer = new Entry[capacity + 1]; }
public bool Enqueue(T value) { if (value == null) throw new ArgumentNullException("value"); int current; int next; do { current = m_head; next = current + 1 == m_buffer.Length ? 0 : current + 1; if (next == m_tail || m_buffer[current].Stored) return false; } while (Interlocked.CompareExchange(ref m_head, next, current) != current); m_buffer[current].Value = value; m_buffer[current].Stored = true; return true; }
public bool Dequeue(out T value) { int current; int next; do { current = m_tail; if (current == m_head || !m_buffer[current].Stored) { value = default(T); return false; } next = current + 1 == m_buffer.Length ? 0 : current + 1; } while (Interlocked.CompareExchange(ref m_tail, next, current) != current); value = m_buffer[current].Value; m_buffer[current].Value = default(T); m_buffer[current].Stored = false; return true; }
private struct Entry { public T Value; public volatile bool Stored; } }
C等ならPUSH、POP等のメモリ操作がいちばん気をつかいそうなところですよね。 VBAでは、適所に Do Eventを2つ入れること(実験により1つではエラー起きやすい)、変数のグローバル宣言にきをつけること(2つのスレッドで同じ変数を呼ばない)ことくらいですかね。プロシージャーは同時に使っても今のところ問題ありません。