[6220] | 1 | using System;
|
---|
| 2 | using System.Collections;
|
---|
| 3 | using System.Collections.Generic;
|
---|
| 4 | using System.Threading;
|
---|
| 5 |
|
---|
| 6 | namespace HeuristicLab.Persistence.Default.Xml {
|
---|
| 7 |
|
---|
| 8 | public class AsyncBuffer<T> : IEnumerable<T>, IEnumerable {
|
---|
| 9 |
|
---|
| 10 | private IEnumerator<T> it;
|
---|
| 11 |
|
---|
| 12 | private Queue<T> queue;
|
---|
| 13 | private object queueLock;
|
---|
| 14 | private AutoResetEvent elementAdded;
|
---|
| 15 | private ManualResetEvent done;
|
---|
| 16 |
|
---|
| 17 | private Thread thread;
|
---|
| 18 |
|
---|
| 19 | private Exception exception;
|
---|
| 20 |
|
---|
| 21 | private class LockIndicator {
|
---|
| 22 | public bool HasLock;
|
---|
| 23 | public LockIndicator() { HasLock = false; }
|
---|
| 24 | }
|
---|
| 25 |
|
---|
| 26 | public AsyncBuffer(IEnumerable<T> source) {
|
---|
| 27 | it = source.GetEnumerator();
|
---|
| 28 | queue = new Queue<T>();
|
---|
| 29 | queueLock = new object();
|
---|
| 30 | elementAdded = new AutoResetEvent(false);
|
---|
| 31 | done = new ManualResetEvent(false);
|
---|
| 32 | thread = new Thread(Run);
|
---|
| 33 | thread.Start();
|
---|
| 34 | }
|
---|
| 35 |
|
---|
| 36 | private void Run() {
|
---|
| 37 | bool hasLock = false;
|
---|
| 38 | try {
|
---|
| 39 | while (it.MoveNext()) {
|
---|
| 40 | T value = it.Current;
|
---|
| 41 | lock (queueLock) {
|
---|
| 42 | queue.Enqueue(value);
|
---|
| 43 | elementAdded.Set();
|
---|
| 44 | }
|
---|
| 45 | }
|
---|
| 46 | } catch (Exception x) {
|
---|
| 47 | exception = x;
|
---|
| 48 | } finally {
|
---|
| 49 | if (hasLock)
|
---|
| 50 | Monitor.Exit(queueLock);
|
---|
| 51 | }
|
---|
| 52 | done.Set();
|
---|
| 53 | }
|
---|
| 54 |
|
---|
| 55 | private IEnumerator<T> RealGetEnumerator(LockIndicator li) {
|
---|
| 56 | Monitor.Enter(queueLock, ref li.HasLock);
|
---|
| 57 | while (!done.WaitOne(0) || queue.Count > 0) {
|
---|
| 58 | while (queue.Count == 0 && !done.WaitOne(0)) {
|
---|
| 59 | li.HasLock = false;
|
---|
| 60 | Monitor.Exit(queueLock);
|
---|
| 61 | AutoResetEvent.WaitAny(new WaitHandle[] { done, elementAdded });
|
---|
| 62 | Monitor.Enter(queueLock, ref li.HasLock);
|
---|
| 63 | }
|
---|
| 64 | if (queue.Count > 0) {
|
---|
| 65 | T element = queue.Dequeue();
|
---|
| 66 | li.HasLock = false;
|
---|
| 67 | Monitor.Exit(queueLock);
|
---|
| 68 | yield return element;
|
---|
| 69 | Monitor.Enter(queueLock, ref li.HasLock);
|
---|
| 70 | }
|
---|
| 71 | }
|
---|
| 72 | li.HasLock = false;
|
---|
| 73 | Monitor.Exit(queueLock);
|
---|
| 74 | if (exception != null)
|
---|
| 75 | throw exception;
|
---|
| 76 | }
|
---|
| 77 |
|
---|
| 78 | #region IEnumerable<T> Members
|
---|
| 79 | public IEnumerator<T> GetEnumerator() {
|
---|
| 80 | LockIndicator li = new LockIndicator();
|
---|
| 81 | try {
|
---|
| 82 | return RealGetEnumerator(li);
|
---|
| 83 | } catch {
|
---|
| 84 | if (li.HasLock)
|
---|
| 85 | Monitor.Exit(queueLock);
|
---|
| 86 | throw;
|
---|
| 87 | }
|
---|
| 88 | }
|
---|
| 89 | #endregion
|
---|
| 90 |
|
---|
| 91 | #region IEnumerable Members
|
---|
| 92 | IEnumerator IEnumerable.GetEnumerator() {
|
---|
| 93 | return GetEnumerator();
|
---|
| 94 | }
|
---|
| 95 | #endregion
|
---|
| 96 | }
|
---|
| 97 | }
|
---|