Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceSpeedUp/HeuristicLab.Persistence/3.3/Default/Xml/AsyncBuffer.cs

Last change on this file was 6220, checked in by epitzer, 14 years ago

Use system wait handles instead of potential spin lock for done signal (#1350)

File size: 2.5 KB
Line 
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.Threading;
5
6namespace 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}
Note: See TracBrowser for help on using the repository browser.