Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.BackgroundProcessing/WorkerMonitor.cs @ 2399

Last change on this file since 2399 was 2399, checked in by epitzer, 15 years ago

Add plugin for background processing. (#769)

File size: 4.2 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using System.ComponentModel;
6using System.Threading;
7using System.Collections.ObjectModel;
8using System.Collections.Specialized;
9using System.Collections;
10
11namespace HeuristicLab.BackgroundProcessing {
12
13
14  /// <summary>
15  /// Provides a list of all currently running or pending ObservableBackgroundWorkers.
16  /// </summary>
17  public class WorkerMonitor : ObservableEnumerable<ObservableBackgroundWorker> {
18
19    public static WorkerMonitor Default = new WorkerMonitor();
20
21    public event ThreadExceptionEventHandler ThreadException;
22    public event NotifyCollectionChangedEventHandler CollectionChanged;
23
24    private List<ObservableBackgroundWorker> BackgroundWorkers;
25    private ReaderWriterLockSlim workerLock;
26
27    public WorkerMonitor() {
28      BackgroundWorkers = new List<ObservableBackgroundWorker>();
29      workerLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
30    }
31
32    internal void RegisterWorker(ObservableBackgroundWorker worker) {
33      worker.RunWorkerCompleted += worker_RunWorkerCompleted;
34      worker.WorkerStopped += worker_WorkerStopped;
35      try {
36        workerLock.EnterUpgradeableReadLock();
37        try {
38          workerLock.EnterWriteLock();
39          BackgroundWorkers.Add(worker);
40        } finally {
41          workerLock.ExitWriteLock();
42        }
43        int index = BackgroundWorkers.Count - 1;
44        OnCollectionChanged(new NotifyCollectionChangedEventArgs(
45          NotifyCollectionChangedAction.Add, worker, index));
46      } finally {
47        workerLock.ExitUpgradeableReadLock();
48      }
49    }
50
51    void worker_WorkerStopped(object sender, EventArgs e) {
52      ObservableBackgroundWorker worker = sender as ObservableBackgroundWorker;
53      try {
54        workerLock.EnterUpgradeableReadLock();
55        int index = BackgroundWorkers.IndexOf(worker);
56        try {
57          workerLock.EnterWriteLock();
58          BackgroundWorkers.RemoveAt(index);
59        } finally {
60          workerLock.ExitWriteLock();
61        }
62        OnCollectionChanged(new NotifyCollectionChangedEventArgs(
63          NotifyCollectionChangedAction.Remove, worker, index));
64      } finally {
65        workerLock.ExitUpgradeableReadLock();
66      }
67    }
68
69    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
70      ObservableBackgroundWorker worker = sender as ObservableBackgroundWorker;
71      if (e.Error != null) {
72        OnThreadException(new Exception(worker.Name, e.Error));
73      }
74    }
75
76    protected void OnThreadException(Exception x) {
77      if (ThreadException != null)
78        ThreadException(this, new ThreadExceptionEventArgs(x));
79    }
80
81    public IEnumerator<ObservableBackgroundWorker> GetEnumerator() {
82      try {
83        workerLock.EnterReadLock();
84        IList<ObservableBackgroundWorker> copy = BackgroundWorkers.ToList();
85        return copy.GetEnumerator();
86      } finally {
87        workerLock.ExitReadLock();
88      }
89    }
90
91    IEnumerator IEnumerable.GetEnumerator() {
92      return GetEnumerator();
93    }
94
95    protected void OnCollectionChanged(NotifyCollectionChangedEventArgs args) {
96      if (CollectionChanged != null)
97        CollectionChanged(this, args);
98    }
99
100    public void CancelAll() {
101      List<ObservableBackgroundWorker> cancelableWorkers = GetCancelableWorkers();
102      lock (cancelableWorkers) {
103        foreach (var worker in cancelableWorkers.ToList()) {
104          worker.WorkerStopped += (sender, args) => {
105            lock (cancelableWorkers) {
106              cancelableWorkers.Remove((ObservableBackgroundWorker)sender);
107              Monitor.Pulse(cancelableWorkers);
108            }
109          };
110          worker.CancelAsync();
111          if (!worker.IsRunning)
112            cancelableWorkers.Remove(worker);
113        }
114        while (cancelableWorkers.Count > 0)
115          Monitor.Wait(cancelableWorkers);
116      }
117    }
118
119    private List<ObservableBackgroundWorker> GetCancelableWorkers() {
120      try {
121        workerLock.EnterReadLock();
122        return BackgroundWorkers.Where(w => w.WorkerSupportsCancellation).ToList();
123      } finally {
124        workerLock.ExitReadLock();
125      }
126    }
127  }
128}
Note: See TracBrowser for help on using the repository browser.