#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
using System;
using System.Threading;
namespace CSharpTest.Net.Synchronization
{
///
/// Creates a lock on a mutex that can be released via the Dispose() method, for use in a using statement
///
public class MutexLock : IDisposable
{
readonly Mutex _mutex;
readonly bool _wasNew, _wasAbandonded;
bool _locked, _disposeMutex;
/// Creates and locks the named mutex
public MutexLock(string name) : this(Timeout.Infinite, name) { }
/// Creates and locks the named mutex
public MutexLock(string format, params object[] args) : this(Timeout.Infinite, String.Format(format, args)) { }
/// Creates and locks the named mutex or throws TimeoutException
/// Raises System.TimeoutException if mutex was not obtained.
public MutexLock(int timeout, string format, params object[] args) : this(timeout, String.Format(format, args)) { }
/// Creates and locks the named mutex or throws TimeoutException
/// Raises System.TimeoutException if mutex was not obtained.
public MutexLock(int timeout, string name)
{
_mutex = new Mutex(true, name, out _wasNew);
_locked = _wasNew;
_disposeMutex = true;
Lock(timeout, ref _wasAbandonded);
}
/// Locks the provided mutex
public MutexLock(Mutex mutex) : this(Timeout.Infinite, mutex) { }
/// Locks the provided mutex or throws TimeoutException
/// Raises System.TimeoutException if mutex was not obtained.
public MutexLock(int timeout, Mutex mutex)
{
_wasNew = false;
_mutex = Check.NotNull(mutex);
_disposeMutex = false;
Lock(timeout, ref _wasAbandonded);
}
/// Returns the mutex
public Mutex MutexHandle { get { return _mutex; } }
/// Returns true if this object holds a lock on the mutex
public bool IsLocked { get { return _locked; } }
/// Returns true if this object created a new named mutex
public bool WasNew { get { return _wasNew; } }
/// Returns true if the lock was obtained from an abandoned mutex
public bool WasAbandonded { get { return _wasAbandonded; } }
private void Lock(int timeout, ref bool wasAbandoned)
{
if (!_locked)
{
wasAbandoned = false;
try
{
_locked = _mutex.WaitOne(timeout, false);
if (!_locked) throw new TimeoutException();
}
catch (AbandonedMutexException)
{ _locked = true; wasAbandoned = true; }
}
}
/// Releases the lock on the mutex, and if created by this closes the mutex
public void Dispose()
{
if (_locked)
{
_mutex.ReleaseMutex();
_locked = false;
}
if (_disposeMutex)
{
_mutex.Close();
_disposeMutex = false;
}
}
}
}