/// <summary> /// Can be disposed from any thread /// </summary> /// <returns></returns> public async Task <IDisposable> LockWriteAsync(int millisecondsTimeout = int.MaxValue) { MyLockQueueItem queueItem; IDisposable answer; lock (_lock) { // If there's no items if (_queue.Count == 0) { // Create a new write entry var newEntry = new MyWriteLockQueueItem(this, true); // Add it to the queue _queue.Add(newEntry); // We're already locked, so just return instantly return(new MyDisposableLock(newEntry)); } // Otherwise, we always just add for write locks else { var newEntry = new MyWriteLockQueueItem(this, alreadyLocked: false); _queue.Add(newEntry); queueItem = newEntry; answer = new MyDisposableLock(newEntry); } } try { await TimeoutTask.Create(queueItem.LockedTask, millisecondsTimeout); } catch (TimeoutException) { queueItem.Release(); throw new TimeoutException("Timeout exceeded and lock not established."); } return(answer); }
/// <summary> /// Can be disposed from any thread /// </summary> /// <returns></returns> public async Task <IDisposable> LockReadAsync(int millisecondsTimeout = int.MaxValue) { MyLockQueueItem queueItem; IDisposable answer; lock (_lock) { // If there's no items if (_queue.Count == 0) { // Create a new read entry var newEntry = new MyReadLockQueueItem(this, true); // Add it to the queue _queue.Add(newEntry); // We're already locked, so just return instantly return(new MyDisposableLock(newEntry)); } // If there's only one item, and it's another read, merge with it if (_queue.Count == 1 && _queue[0] is MyReadLockQueueItem) { (_queue[0] as MyReadLockQueueItem).Add(); // We're already locked, so just return instantly return(new MyDisposableLock(_queue[0])); } // If there's a read at the end, merge with it else if (_queue.Last() is MyReadLockQueueItem) { var last = _queue.Last() as MyReadLockQueueItem; last.Add(); // Need to wait till this one starts queueItem = last; answer = new MyDisposableLock(last); } // Otherwise, the last item is a write, so we need to add new and wait else { var newEntry = new MyReadLockQueueItem(this, alreadyLocked: false); _queue.Add(newEntry); queueItem = newEntry; answer = new MyDisposableLock(newEntry); } } try { await TimeoutTask.Create(queueItem.LockedTask, millisecondsTimeout); } catch (TimeoutException) { queueItem.Release(); throw new TimeoutException("Timeout exceeded and lock not established."); } return(answer); }