2using System.Collections.Generic;
4using System.Threading.Tasks;
15 private readonly
string creatorStacktrace;
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;
43 this.creatorStacktrace = Environment.StackTrace;
50 public object Owner => this.owner;
56 public string CreatorStacktrace => this.creatorStacktrace;
68 return this.nrReaders;
82 return this.nrReaders > 0;
96 return this.isWriting;
110 return this.nrReaders > 0 || this.isWriting;
123 if (this.nrReaders <= 0)
124 throw new InvalidOperationException(
"Not in a reading state.");
137 throw new InvalidOperationException(
"Not in a writing state.");
149 if (this.nrReaders <= 0 && !this.isWriting)
150 throw new InvalidOperationException(
"Not in a reading or writing state.");
178 TaskCompletionSource<bool> Wait =
null;
186 if (this.nrReaders == 0)
189 return ++this.nrReaders;
193 Wait =
new TaskCompletionSource<bool>();
194 this.noWriters.AddLast(Wait);
209 LinkedList<TaskCompletionSource<bool>> List =
null;
213 if (this.nrReaders <= 0)
214 throw new InvalidOperationException(
"Not in a reading state.");
217 if (this.nrReaders == 0)
220 return Task.FromResult<
int>(this.nrReaders);
222 if (this.noReadersOrWriters.First is
null)
223 return Task.FromResult<
int>(0);
225 List = this.noReadersOrWriters;
226 this.noReadersOrWriters =
new LinkedList<TaskCompletionSource<bool>>();
229 foreach (TaskCompletionSource<bool> T
in List)
230 T.TrySetResult(
true);
232 return Task.FromResult<
int>(0);
242 TaskCompletionSource<bool> Wait =
null;
243 DateTime Start = DateTime.Now;
251 if (this.nrReaders == 0)
257 else if (Timeout <= 0)
261 Wait =
new TaskCompletionSource<bool>();
262 this.noWriters.AddLast(Wait);
266 using (Timer Timer =
new Timer((P) =>
268 Wait.TrySetResult(
false);
270 },
null, Timeout, System.Threading.Timeout.Infinite))
272 DateTime Now = DateTime.Now;
273 bool Result = await Wait.Task;
278 this.noWriters.Remove(Wait);
284 Timeout -= (int)((Now - Start).TotalMilliseconds + 0.5);
296 TaskCompletionSource<bool> Prev =
null;
297 TaskCompletionSource<bool> Wait =
null;
304 this.noWriters.Remove(Prev);
306 if (this.nrReaders == 0 && !this.isWriting)
309 this.isWriting =
true;
314 Wait =
new TaskCompletionSource<bool>();
315 this.noReadersOrWriters.AddLast(Wait);
316 this.noWriters.AddLast(Wait);
331 LinkedList<TaskCompletionSource<bool>> List =
null;
332 LinkedList<TaskCompletionSource<bool>> List2 =
null;
337 throw new InvalidOperationException(
"Not in a writing state.");
340 this.isWriting =
false;
342 if (!(this.noReadersOrWriters.First is
null))
344 List = this.noReadersOrWriters;
345 this.noReadersOrWriters =
new LinkedList<TaskCompletionSource<bool>>();
348 if (!(this.noWriters.First is
null))
350 List2 = this.noWriters;
351 this.noWriters =
new LinkedList<TaskCompletionSource<bool>>();
357 foreach (TaskCompletionSource<bool> T
in List)
358 T.TrySetResult(
true);
361 if (!(List2 is
null))
363 foreach (TaskCompletionSource<bool> T
in List2)
364 T.TrySetResult(
true);
367 return Task.CompletedTask;
377 TaskCompletionSource<bool> Prev =
null;
378 TaskCompletionSource<bool> Wait =
null;
379 DateTime Start = DateTime.Now;
386 this.noWriters.Remove(Prev);
388 if (this.nrReaders == 0 && !this.isWriting)
391 this.isWriting =
true;
394 else if (Timeout <= 0)
398 Wait =
new TaskCompletionSource<bool>();
399 this.noWriters.AddLast(Wait);
400 this.noReadersOrWriters.AddLast(Wait);
404 using (Timer Timer =
new Timer((P) =>
406 Wait.TrySetResult(
false);
408 },
null, Timeout, System.Threading.Timeout.Infinite))
410 DateTime Now = DateTime.Now;
411 bool Result = await Wait.Task;
416 this.noWriters.Remove(Wait);
417 this.noReadersOrWriters.Remove(Wait);
423 Timeout -= (int)((Now - Start).TotalMilliseconds + 0.5);
435 LinkedList<TaskCompletionSource<bool>> List =
null;
436 LinkedList<TaskCompletionSource<bool>> List2 =
null;
441 this.isWriting =
false;
444 if (!(this.noReadersOrWriters.First is
null))
446 List = this.noReadersOrWriters;
447 this.noReadersOrWriters =
new LinkedList<TaskCompletionSource<bool>>();
450 if (!(this.noWriters.First is
null))
452 List2 = this.noWriters;
453 this.noWriters =
new LinkedList<TaskCompletionSource<bool>>();
459 foreach (TaskCompletionSource<bool> T
in List)
460 T.TrySetResult(
false);
463 if (!(List2 is
null))
465 foreach (TaskCompletionSource<bool> T
in List2)
466 T.TrySetResult(
false);
469 return Task.CompletedTask;
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...
int NrReaders
Number of concurrent readers.
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.
bool IsWriting
If the object has a writer.
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...
object Owner
Owner of object.
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....
virtual void Dispose()
IDisposable.Dispose
An interface for objects that allow single concurrent writers but multiple concurrent readers.