-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclsResponseList.cs
215 lines (193 loc) · 6.87 KB
/
clsResponseList.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
using System;
using System.Collections.Generic;
using System.Threading;
using System.Diagnostics;
namespace HSPI_ENVIRACOM_MANAGER
{
/// <summary>
/// Wrapper class for the work to be done.
/// </summary>
/// <typeparam s="T"></typeparam>
public class PeriodicListEventArgs<T> : EventArgs
{
protected T work;
public T Work
{
get { return work; }
}
public PeriodicListEventArgs(T work)
{
this.work = work;
}
}
/// <summary>
/// Wrapper class for recording an exception that occurred while processing the work packet.
/// </summary>
public class PeriodicListExceptionEventArgs : EventArgs
{
protected Exception exception;
public Exception Exception
{
get { return exception; }
}
public PeriodicListExceptionEventArgs(Exception e)
{
exception = e;
}
}
/// <summary>
/// A re-usable class for processing items repeatedly in a worker thread until the item indicates work is done.
/// </summary>
public class PeriodicList<T>
{
public delegate bool DoResponseDlgt(object sender, PeriodicListEventArgs<T> args);
public delegate bool DoPeriodicDlgt(object sender, PeriodicListEventArgs<T> args);
public delegate void DoExceptionDlgt(object sender, PeriodicListExceptionEventArgs args);
public event DoResponseDlgt DoResponse;
public event DoPeriodicDlgt DoPeriodic;
public event DoExceptionDlgt DoException;
protected Thread processThread;
protected List<T> workList;
protected EventWaitHandle waitProcess;
protected bool stop;
protected TimeSpan waitPeriod;
/// <summary>
/// Constructor. Initializes the work list, wait process, and processing thread.
/// </summary>
public PeriodicList(TimeSpan period)
{
workList = new List<T>();
waitProcess = new EventWaitHandle(false, EventResetMode.AutoReset);
waitPeriod = period;
processThread = new Thread(new ThreadStart(ProcessPeriodicList));
processThread.IsBackground = true;
processThread.Start();
}
/// <summary>
/// Enqueue a work item.
/// </summary>
/// <param s="work"></param>
public void AddToPeriodicList(T work)
{
lock (workList)
{
workList.Add(work);
}
waitProcess.Set();
}
/// <summary>
/// This method accepts a predicate to match the item in the list and calls the OnDoResponse method.
/// If the DoResponse handler returns true, then removes the matching item from the list.
/// </summary>
/// <param s="match"></param>
public virtual void ProcessResponse(Predicate<T> match)
{
lock (workList)
{
T work = workList.Find(match);
clsEnviracomApp.TraceEvent(TraceEventType.Verbose, "PeriodicList<T>::RemoveFromPeriodicList: processing response");
if (OnDoResponse(new PeriodicListEventArgs<T>(work)) == true)
workList.Remove(work);
}
}
/// <summary>
/// Stop the work processing thread.
/// </summary>
public void Stop()
{
stop = true;
waitProcess.Set();
}
/// <summary>
/// Process queued work.
/// </summary>
protected void ProcessPeriodicList()
{
while (!stop)
{
// Wait for some work.
clsEnviracomApp.TraceEvent(TraceEventType.Verbose, "PeriodicList<T>::ProcessPeriodicList: waiting for work");
waitProcess.WaitOne();
bool haveWork = false;
// Finish remaining work before stopping.
do
{
// Assume no work.
haveWork = false;
// Prevent enqueing from a different thread.
lock (workList)
{
// Do we have work? This might be 0 if stopping or if all work is processed.
if (workList.Count > 0)
{
// Yes, we have work.
haveWork = true;
// Get the work.
foreach (T work in workList)
{
try
{
// Try processing it.
if (OnDoPeriodic(new PeriodicListEventArgs<T>(work)) == true)
workList.Remove(work);
clsEnviracomApp.TraceEvent(TraceEventType.Verbose, "PeriodicList<T>::ProcessPeriodicList: ");
}
catch (Exception e)
{
// Oops, inform application of a work error.
OnWorkException(new PeriodicListExceptionEventArgs(e));
workList.Remove(work);
clsEnviracomApp.TraceEvent(TraceEventType.Verbose, "PeriodicList<T>::ProcessPeriodicList: reporting exception: " + e.ToString());
}
}
}
}
Thread.Sleep(waitPeriod);
} while (haveWork); // continue processing if there was work.
}
}
/// <summary>
/// Override this method if you want to handle periodic actions in a derived class. This method
/// calls any events wired in to the DoPeriodic event.
/// </summary>
/// <param s="workEventArgs"></param>
protected virtual bool OnDoPeriodic(PeriodicListEventArgs<T> workEventArgs)
{
if (DoPeriodic != null)
{
clsEnviracomApp.TraceEvent(TraceEventType.Verbose, "PeriodicList<T>::OnDoPeriodic: calling periodic handler");
return DoPeriodic(this, workEventArgs);
}
else
return true;
}
/// <summary>
/// Override this method if you want to handle response actions in a derived class. This method
/// calls any events wired in to the DoResponse event.
/// </summary>
/// <param s="workEventArgs"></param>
protected virtual bool OnDoResponse(PeriodicListEventArgs<T> workEventArgs)
{
if (DoResponse != null)
{
clsEnviracomApp.TraceEvent(TraceEventType.Verbose, "PeriodicList<T>::OnDoResponse: calling response handler");
return DoResponse(this, workEventArgs);
}
else
return true;
}
/// <summary>
/// Override this method if you want to handle work exceptions in a derived class.
/// This method calls any events wired in to the DoException event.
/// </summary>
/// <param s="workExceptionArgs"></param>
protected virtual void OnWorkException(PeriodicListExceptionEventArgs workExceptionArgs)
{
if (DoException != null)
{
DoException(this, workExceptionArgs);
}
clsEnviracomApp.TraceEvent(TraceEventType.Verbose, "PeriodicList<T>::OnWorkException: calling exception handler");
}
}
}