Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
AsyncProcessor.cs
1using System;
3using System.Threading;
4using System.Threading.Tasks;
5using Waher.Events;
6
8{
13 where T : class, IWorkItem
14 {
15 private readonly CancellationTokenSource[] cancelWaitSources;
16 private readonly CancellationTokenSource[] cancelWorkSources;
17 private readonly T[] currentWorkItem;
18 private readonly Task[] processors;
19 private readonly string name;
20 private readonly int nrProcessors;
21 private LinkedListNode<IAsyncProcessor> processorNode;
22 private AsyncQueue<T> queue = new AsyncQueue<T>();
23 private int nrProcessorsRunning;
24 private bool terminating = false;
25 private bool terminated = false;
26 private bool idle = true;
27
32 [Obsolete("Use the constructor with a Name argument.")]
33 public AsyncProcessor(int NrProcessors)
34 : this(NrProcessors, Guid.NewGuid().ToString())
35 {
36 }
37
43 public AsyncProcessor(int NrProcessors, string Name)
44 {
45 if (NrProcessors <= 0)
46 throw new ArgumentException("Number of processors must be positive.", nameof(NrProcessors));
47
48 int i;
49
50 this.name = Name;
51 this.nrProcessors = this.nrProcessorsRunning = NrProcessors;
52 this.processors = new Task[NrProcessors];
53
54 this.cancelWaitSources = new CancellationTokenSource[NrProcessors];
55 this.cancelWorkSources = new CancellationTokenSource[NrProcessors];
56 this.currentWorkItem = new T[NrProcessors];
57 this.processorNode = AsyncProcessors.RegisterProcessor(this);
58
59 for (i = 0; i < this.nrProcessors; i++)
60 this.processors[i] = this.PerformWork(i);
61 }
62
66 [Obsolete("Use the DisposeAsync() method.")]
67 public void Dispose()
68 {
69 this.DisposeAsync().Wait();
70 }
71
75 public async Task DisposeAsync()
76 {
77 this.terminating = true;
78
79 if (!(this.processorNode is null))
80 {
81 AsyncProcessors.UnregisterProcessor(this.processorNode);
82 this.processorNode = null;
83 }
84
85 if (!this.terminated)
86 {
87 for (int i = 0; i < this.nrProcessors; i++)
88 {
89 this.cancelWaitSources[i]?.Cancel();
90 this.cancelWorkSources[i]?.Cancel();
91 }
92
93 await Task.WhenAll(this.processors);
94 this.terminated = true;
95 }
96
97 this.queue?.Dispose();
98 this.queue = null;
99 }
100
105 {
106 _ = this.CloseForTermination(false, 0);
107 }
108
115 public Task CloseForTermination(bool WaitForCompletion)
116 {
117 return this.CloseForTermination(WaitForCompletion, int.MaxValue);
118 }
119
128 public async Task CloseForTermination(bool WaitForCompletion, int Timeout)
129 {
130 try
131 {
132 this.terminating = true;
133
134 for (int i = 0; i < this.nrProcessors; i++)
135 this.cancelWaitSources[i]?.Cancel();
136
137 if (!this.terminated && Timeout > 0)
138 {
139 if (Timeout > 0 && Timeout < int.MaxValue)
140 {
141 _ = Task.Delay(Timeout).ContinueWith((_) =>
142 {
143 for (int i = 0; i < this.nrProcessors; i++)
144 this.cancelWorkSources[i]?.Cancel();
145 });
146 }
147
148 if (WaitForCompletion)
149 await Task.WhenAll(this.processors);
150
151 this.terminated = true;
152 }
153 }
154 catch (Exception ex)
155 {
156 Log.Exception(ex);
157 }
158 }
159
165 public void Queue(T Work)
166 {
167 if (!this.terminating)
168 {
169 this.idle = false;
170 this.queue?.Queue(Work);
171 }
172 }
173
179 public Task<bool> Forward(T Work)
180 {
181 if (!this.terminating)
182 {
183 this.idle = false;
184 return this.queue?.Forward(Work) ?? Task.FromResult(false);
185 }
186 else
187 return Task.FromResult(false);
188 }
189
193 public string Name => this.name;
194
198 public bool Terminating => this.terminating;
199
203 public bool Terminated => this.terminated;
204
208 public int QueueSize => this.queue?.CountItems ?? 0;
209
213 public bool Idle => this.idle;
214
219 private async Task PerformWork(int ProcessorIndex)
220 {
221 try
222 {
223 ProcessorEventArgs e = new ProcessorEventArgs(ProcessorIndex);
224 T Item;
225 Task<T> Task;
226
227 while (true)
228 {
229 if (this.terminating)
230 {
231 if (!(this.queue?.TryGetItem(out Item) ?? false))
232 break;
233 }
234 else
235 {
236 using (CancellationTokenSource Cancel = new CancellationTokenSource())
237 {
238 this.cancelWaitSources[ProcessorIndex] = Cancel;
239 try
240 {
241 Task = this.queue?.Wait(Cancel.Token);
242 if (Task is null)
243 break;
244
245 if (!Task.IsCompleted && this.queue.CountSubscribers == this.nrProcessors)
246 {
247 this.idle = true;
248 await this.OnIdle.Raise(this, e);
249 }
250
251 Item = await Task;
252 if (Item is null)
253 break;
254 }
255 finally
256 {
257 this.cancelWaitSources[ProcessorIndex] = null;
258 }
259 }
260 }
261
262 this.idle = false;
263
264 using (CancellationTokenSource Cancel = new CancellationTokenSource())
265 {
266 this.cancelWorkSources[ProcessorIndex] = Cancel;
267 this.currentWorkItem[ProcessorIndex] = Item;
268 try
269 {
270 await Item.Execute(Cancel.Token);
271 Item.Processed(!Cancel.IsCancellationRequested);
272 }
273 catch (Exception ex)
274 {
275 Item.Processed(false);
276 Log.Exception(ex);
277 }
278 finally
279 {
280 this.cancelWorkSources[ProcessorIndex] = null;
281 this.currentWorkItem[ProcessorIndex] = default;
282 }
283 }
284 }
285 }
286 catch (Exception ex)
287 {
288 Log.Exception(ex);
289 }
290
291 if (--this.nrProcessorsRunning == 0)
292 this.terminated = true;
293 }
294
299 public event EventHandlerAsync<ProcessorEventArgs> OnIdle;
300
304 public async Task WaitUntilIdle()
305 {
306 TaskCompletionSource<bool> Idle = new TaskCompletionSource<bool>();
307
308 Task OnIdle(object Sender, EventArgs e)
309 {
310 Task.Run(() => Idle.TrySetResult(true));
311 return Task.CompletedTask;
312 }
313 ;
314
315 this.OnIdle += OnIdle;
316 try
317 {
318 if (this.idle)
319 return;
320
321 await Idle.Task;
322 }
323 finally
324 {
325 this.OnIdle -= OnIdle;
326 }
327 }
328 }
329}
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:14
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
Definition: Log.cs:1657
Processes work tasks, in an asynchronous manner.
bool Terminating
If the console worker is being terminated.
void CloseForTermination()
Closes the processor for new items, but continues to process queued items.
void Dispose()
Stops processing tasks and disposes the queue.
bool Terminated
If the console worker has been terminated.
async Task DisposeAsync()
Stops processing tasks and disposes the queue.
Task CloseForTermination(bool WaitForCompletion)
Closes the processor for new items. If WaitForCompletion is true, the method waits for queued items ...
async Task WaitUntilIdle()
Waits until the processor becomes idle.
bool Idle
If processor is idle
AsyncProcessor(int NrProcessors)
Processes work tasks, in an asynchronous manner.
AsyncProcessor(int NrProcessors, string Name)
Processes work tasks, in an asynchronous manner.
string Name
Name of processor.
EventHandlerAsync< ProcessorEventArgs > OnIdle
Event raised when the processor becomes idle. It can be raised multiple times if more than one proces...
int QueueSize
Number of items in queue.
void Queue(T Work)
Queues a work item for processing. No information is returned wether the item was forwarded or discar...
Task< bool > Forward(T Work)
Forwards a work item for processing.
async Task CloseForTermination(bool WaitForCompletion, int Timeout)
Closes the processor for new items. If WaitForCompletion is true, the method waits for queued items ...
Maintains a record of active processors.
Asynchronous First-in-First-out (FIFO) Queue, for use when transporting items of type T between task...
Definition: AsyncQueue.cs:16
Task< bool > Forward(T Item)
Processes an item by adding it last in the queue.
Definition: AsyncQueue.cs:239
Task< T > Wait()
Waits indefinitely (or until queue is disposed) for an item to be available. If Queue is disposed,...
Definition: AsyncQueue.cs:327
void Queue(T Item)
Queues an item for processing by adding it last in the queue. No information is returned wether the i...
Definition: AsyncQueue.cs:160
void Dispose()
IDisposable.Dispose
Definition: AsyncQueue.cs:539
int CountItems
Number of items in queue.
Definition: AsyncQueue.cs:58
Event arguments for processor events.
Interface for AsyncProcessor<T> instances.
Interface for asynchronous operations.
Definition: IWorkItem.cs:10
Definition: ImplTypes.g.cs:58