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 | }
|
---|