#region Copyright 2010-2014 by Roger Knapp, Licensed under the Apache License, Version 2.0
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
#define SUPPORT_RECURSION
using System;
using System.Threading;
namespace CSharpTest.Net.Synchronization
{
///
/// provides a simple and fast, writer only lock, request for read immediatly return true.
///
public class ReservedWriteLocking : ReservedWriteLocking
where T : ILockStrategy, new()
{
/// Constructs the reader-writer lock using a new T()
public ReservedWriteLocking() : base(new T())
{ }
}
///
/// provides a simple and fast, writer only lock, request for read immediatly return true.
///
public class ReservedWriteLocking : ILockStrategy
{
/// The syncronization object writers and potential readers use to lock
object _sync;
/// The underlying lock that will be acquired directly by Read() and after the 2nd call to Write()
ILockStrategy _lock;
/// The current count of the calls to Write()
int _writeCount;
///
/// Constructs the reader-writer lock using the lock provided
///
public ReservedWriteLocking(ILockStrategy lck)
{
_sync = this;
_lock = Check.NotNull(lck);
}
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
public virtual void Dispose()
{
object exit = Interlocked.Exchange(ref _sync, null);
if (exit == null)
return;
_lock.Dispose();
Check.Assert(_writeCount == 0);
}
/// Changes every time a write lock is aquired. If WriteVersion == 0, no write locks have been issued.
public int WriteVersion { get { return _lock.WriteVersion; } }
///
/// Returns true if the lock was successfully obtained within the timeout specified
///
public bool TryRead(int millisecondsTimeout)
{
return _lock.TryRead(millisecondsTimeout);
}
///
/// Releases a read lock
///
public void ReleaseRead()
{
_lock.ReleaseRead();
}
///
/// The first call reserves the Write lock for the current thread but does not stop reader access
/// until the write lock is acquired again.
///
public virtual bool TryWrite(int millisecondsTimeout)
{
if (_sync == null) throw new ObjectDisposedException(GetType().FullName);
// First obtain the 'writer lock':
if (!Monitor.TryEnter(_sync, millisecondsTimeout))
return false;
if (_writeCount == 0)
{
_writeCount++;
return true;
}
if (_lock.TryWrite(millisecondsTimeout))
{
_writeCount++;
return true;
}
return false;
}
///
/// Releases a writer lock
///
public void ReleaseWrite()
{
Check.Assert(_writeCount > 0);
_writeCount--;
if (_writeCount > 0)
_lock.ReleaseWrite();
Monitor.Exit(_sync);
}
///
/// Returns a reader lock that can be elevated to a write lock
///
public ReadLock Read() { return ReadLock.Acquire(this, -1); }
///
/// Returns a reader lock that can be elevated to a write lock
///
///
public ReadLock Read(int millisecondsTimeout) { return ReadLock.Acquire(this, millisecondsTimeout); }
///
/// Returns a read and write lock
///
public WriteLock Write() { return WriteLock.Acquire(this, -1); }
///
/// Returns a read and write lock
///
///
public WriteLock Write(int millisecondsTimeout) { return WriteLock.Acquire(this, millisecondsTimeout); }
}
}