Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
MultiReadSingleWriteObject.cs
1using System;
2using System.Collections.Generic;
3using System.Threading;
4using System.Threading.Tasks;
5
7{
13 {
14#if DEBUG
15 private readonly string creatorStacktrace;
16#endif
17 private readonly object owner;
18 private LinkedList<TaskCompletionSource<bool>> noWriters = new LinkedList<TaskCompletionSource<bool>>();
19 private LinkedList<TaskCompletionSource<bool>> noReadersOrWriters = new LinkedList<TaskCompletionSource<bool>>();
20 private readonly object synchObj = new object();
21 private long token = 0;
22 private int nrReaders = 0;
23 private bool isWriting = false;
24
31 : this()
32 {
33 this.owner = Owner;
34 }
35
41 {
42#if DEBUG
43 this.creatorStacktrace = Environment.StackTrace;
44#endif
45 }
46
50 public object Owner => this.owner;
51
52#if DEBUG
56 public string CreatorStacktrace => this.creatorStacktrace;
57#endif
58
62 public int NrReaders
63 {
64 get
65 {
66 lock (this.synchObj)
67 {
68 return this.nrReaders;
69 }
70 }
71 }
72
76 public bool IsReading
77 {
78 get
79 {
80 lock (this.synchObj)
81 {
82 return this.nrReaders > 0;
83 }
84 }
85 }
86
90 public bool IsWriting
91 {
92 get
93 {
94 lock (this.synchObj)
95 {
96 return this.isWriting;
97 }
98 }
99 }
100
105 {
106 get
107 {
108 lock (this.synchObj)
109 {
110 return this.nrReaders > 0 || this.isWriting;
111 }
112 }
113 }
114
119 public void AssertReading()
120 {
121 lock (this.synchObj)
122 {
123 if (this.nrReaders <= 0)
124 throw new InvalidOperationException("Not in a reading state.");
125 }
126 }
127
132 public void AssertWriting()
133 {
134 lock (this.synchObj)
135 {
136 if (!this.isWriting)
137 throw new InvalidOperationException("Not in a writing state.");
138 }
139 }
140
146 {
147 lock (this.synchObj)
148 {
149 if (this.nrReaders <= 0 && !this.isWriting)
150 throw new InvalidOperationException("Not in a reading or writing state.");
151 }
152 }
153
160 public long Token
161 {
162 get
163 {
164 lock (this.synchObj)
165 {
166 return this.token;
167 }
168 }
169 }
170
176 public virtual async Task<int> BeginRead()
177 {
178 TaskCompletionSource<bool> Wait = null;
179
180 while (true)
181 {
182 lock (this.synchObj)
183 {
184 if (!this.isWriting)
185 {
186 if (this.nrReaders == 0)
187 this.token++;
188
189 return ++this.nrReaders;
190 }
191 else
192 {
193 Wait = new TaskCompletionSource<bool>();
194 this.noWriters.AddLast(Wait);
195 }
196 }
197
198 await Wait.Task;
199 }
200 }
201
207 public virtual Task<int> EndRead()
208 {
209 LinkedList<TaskCompletionSource<bool>> List = null;
210
211 lock (this.synchObj)
212 {
213 if (this.nrReaders <= 0)
214 throw new InvalidOperationException("Not in a reading state.");
215
216 this.nrReaders--;
217 if (this.nrReaders == 0)
218 this.token++;
219 else
220 return Task.FromResult<int>(this.nrReaders);
221
222 if (this.noReadersOrWriters.First is null)
223 return Task.FromResult<int>(0);
224
225 List = this.noReadersOrWriters;
226 this.noReadersOrWriters = new LinkedList<TaskCompletionSource<bool>>();
227 }
228
229 foreach (TaskCompletionSource<bool> T in List)
230 T.TrySetResult(true);
231
232 return Task.FromResult<int>(0);
233 }
234
240 public virtual async Task<bool> TryBeginRead(int Timeout)
241 {
242 TaskCompletionSource<bool> Wait = null;
243 DateTime Start = DateTime.Now;
244
245 while (true)
246 {
247 lock (this.synchObj)
248 {
249 if (!this.isWriting)
250 {
251 if (this.nrReaders == 0)
252 this.token++;
253
254 this.nrReaders++;
255 return true;
256 }
257 else if (Timeout <= 0)
258 return false;
259 else
260 {
261 Wait = new TaskCompletionSource<bool>();
262 this.noWriters.AddLast(Wait);
263 }
264 }
265
266 using (Timer Timer = new Timer((P) =>
267 {
268 Wait.TrySetResult(false);
269
270 }, null, Timeout, System.Threading.Timeout.Infinite))
271 {
272 DateTime Now = DateTime.Now;
273 bool Result = await Wait.Task;
274 if (!Result)
275 {
276 lock (this.synchObj)
277 {
278 this.noWriters.Remove(Wait);
279 }
280
281 return false;
282 }
283
284 Timeout -= (int)((Now - Start).TotalMilliseconds + 0.5);
285 Start = Now;
286 }
287 }
288 }
289
294 public virtual async Task BeginWrite()
295 {
296 TaskCompletionSource<bool> Prev = null;
297 TaskCompletionSource<bool> Wait = null;
298
299 while (true)
300 {
301 lock (this.synchObj)
302 {
303 if (!(Prev is null))
304 this.noWriters.Remove(Prev); // In case previously locked for reading
305
306 if (this.nrReaders == 0 && !this.isWriting)
307 {
308 this.token++;
309 this.isWriting = true;
310 return;
311 }
312 else
313 {
314 Wait = new TaskCompletionSource<bool>();
315 this.noReadersOrWriters.AddLast(Wait);
316 this.noWriters.AddLast(Wait);
317 }
318 }
319
320 await Wait.Task;
321 Prev = Wait;
322 }
323 }
324
329 public virtual Task EndWrite()
330 {
331 LinkedList<TaskCompletionSource<bool>> List = null;
332 LinkedList<TaskCompletionSource<bool>> List2 = null;
333
334 lock (this.synchObj)
335 {
336 if (!this.isWriting)
337 throw new InvalidOperationException("Not in a writing state.");
338
339 this.token++;
340 this.isWriting = false;
341
342 if (!(this.noReadersOrWriters.First is null))
343 {
344 List = this.noReadersOrWriters;
345 this.noReadersOrWriters = new LinkedList<TaskCompletionSource<bool>>();
346 }
347
348 if (!(this.noWriters.First is null))
349 {
350 List2 = this.noWriters;
351 this.noWriters = new LinkedList<TaskCompletionSource<bool>>();
352 }
353 }
354
355 if (!(List is null))
356 {
357 foreach (TaskCompletionSource<bool> T in List)
358 T.TrySetResult(true);
359 }
360
361 if (!(List2 is null))
362 {
363 foreach (TaskCompletionSource<bool> T in List2)
364 T.TrySetResult(true);
365 }
366
367 return Task.CompletedTask;
368 }
369
375 public virtual async Task<bool> TryBeginWrite(int Timeout)
376 {
377 TaskCompletionSource<bool> Prev = null;
378 TaskCompletionSource<bool> Wait = null;
379 DateTime Start = DateTime.Now;
380
381 while (true)
382 {
383 lock (this.synchObj)
384 {
385 if (!(Prev is null))
386 this.noWriters.Remove(Prev); // In case previously locked for reading
387
388 if (this.nrReaders == 0 && !this.isWriting)
389 {
390 this.token++;
391 this.isWriting = true;
392 return true;
393 }
394 else if (Timeout <= 0)
395 return false;
396 else
397 {
398 Wait = new TaskCompletionSource<bool>();
399 this.noWriters.AddLast(Wait);
400 this.noReadersOrWriters.AddLast(Wait);
401 }
402 }
403
404 using (Timer Timer = new Timer((P) =>
405 {
406 Wait.TrySetResult(false);
407
408 }, null, Timeout, System.Threading.Timeout.Infinite))
409 {
410 DateTime Now = DateTime.Now;
411 bool Result = await Wait.Task;
412 if (!Result)
413 {
414 lock (this.synchObj)
415 {
416 this.noWriters.Remove(Wait);
417 this.noReadersOrWriters.Remove(Wait);
418 }
419
420 return false;
421 }
422
423 Timeout -= (int)((Now - Start).TotalMilliseconds + 0.5);
424 Start = Now;
425 Prev = Wait;
426 }
427 }
428 }
429
433 public virtual Task Unlock()
434 {
435 LinkedList<TaskCompletionSource<bool>> List = null;
436 LinkedList<TaskCompletionSource<bool>> List2 = null;
437
438 lock (this.synchObj)
439 {
440 this.nrReaders = 0;
441 this.isWriting = false;
442 this.token++;
443
444 if (!(this.noReadersOrWriters.First is null))
445 {
446 List = this.noReadersOrWriters;
447 this.noReadersOrWriters = new LinkedList<TaskCompletionSource<bool>>();
448 }
449
450 if (!(this.noWriters.First is null))
451 {
452 List2 = this.noWriters;
453 this.noWriters = new LinkedList<TaskCompletionSource<bool>>();
454 }
455 }
456
457 if (!(List is null))
458 {
459 foreach (TaskCompletionSource<bool> T in List)
460 T.TrySetResult(false);
461 }
462
463 if (!(List2 is null))
464 {
465 foreach (TaskCompletionSource<bool> T in List2)
466 T.TrySetResult(false);
467 }
468
469 return Task.CompletedTask;
470 }
471
475 public virtual void Dispose()
476 {
477 this.Unlock();
478 }
479
480 }
481}
Represents an object that allows single concurrent writers but multiple concurrent readers....
void AssertReading()
Throws an InvalidOperationException if the object is not in a reading state.
MultiReadSingleWriteObject()
Represents an object that allows single concurrent writers but multiple concurrent readers....
virtual async Task< bool > TryBeginRead(int Timeout)
Waits, at most Timeout milliseconds, until object ready for reading. Each successful call to TryBegi...
virtual Task EndWrite()
Ends a writing session of the object. Must be called once for each call to BeginWrite or successful c...
void AssertReadingOrWriting()
Throws an InvalidOperationException if the object is not in a reading or writing state.
virtual Task Unlock()
Unlocks all locks on the object.
bool IsReading
If the object is in a reading state.
long Token
Returns a token corresponding to the current lock. It is incremented at the start of a lock-cycle (wh...
virtual async Task< bool > TryBeginWrite(int Timeout)
Waits, at most Timeout milliseconds, until object ready for writing. Each successful call to TryBegi...
virtual async Task BeginWrite()
Waits until object ready for writing. Each call to BeginWrite must be followed by exactly one call to...
virtual Task< int > EndRead()
Ends a reading session of the object. Must be called once for each call to BeginRead or successful ca...
void AssertWriting()
Throws an InvalidOperationException if the object is not in a writing state.
bool IsReadingOrWriting
If the object is locked for reading or writing.
virtual async Task< int > BeginRead()
Waits until object ready for reading. Each call to BeginRead must be followed by exactly one call to ...
MultiReadSingleWriteObject(object Owner)
Represents an object that allows single concurrent writers but multiple concurrent readers....
An interface for objects that allow single concurrent writers but multiple concurrent readers.