##// END OF EJS Templates
missing file
missing file

File last commit:

r136:e9e7940c7d98 v2
r258:d0876436d95d v3
Show More
SharedLock.cs
202 lines | 6.3 KiB | text/x-csharp | CSharpLexer
using System;
using System.Threading;
using System.Diagnostics;
namespace Implab.Parallels {
/// <summary>
/// Implements a lightweight mechanism to aquire a shared or an exclusive lock.
/// </summary>
public class SharedLock {
readonly object m_lock = new object();
// the count of locks currently acquired by clients
int m_locks;
// the count of pending requests for upgrade
int m_upgrades;
bool m_exclusive;
public bool LockExclusive(int timeout) {
lock (m_lock) {
var dt = timeout;
if (m_locks > m_upgrades) {
var t1 = Environment.TickCount;
do {
if (!Monitor.Wait(m_lock, timeout))
return false;
if (m_locks == m_upgrades)
break;
if (timeout > 0) {
dt = timeout - Environment.TickCount + t1;
if (dt < 0)
return false;
}
} while(true);
}
m_exclusive = true;
m_locks ++;
return true;
}
}
public void LockExclusive() {
lock (m_lock) {
while (m_locks > m_upgrades)
Monitor.Wait(m_lock);
m_exclusive = true;
m_locks ++;
}
}
/// <summary>
/// Acquires a shared lock.
/// </summary>
/// <returns><c>true</c>, if the shared lock was acquired, <c>false</c> if the specified timeout was expired.</returns>
/// <param name="timeout">Timeout.</param>
public bool LockShared(int timeout) {
lock (m_lock) {
if (!m_exclusive) {
m_locks++;
return true;
}
if (m_locks == m_upgrades) {
m_exclusive = false;
m_locks = 1;
return true;
}
var t1 = Environment.TickCount;
var dt = timeout;
do {
if (!Monitor.Wait(m_lock, dt))
return false;
if (m_locks == m_upgrades || !m_exclusive)
break;
if (timeout >= 0) {
dt = timeout - Environment.TickCount + t1;
if (dt < 0)
return false;
}
} while(true);
m_locks ++;
m_exclusive = false;
return true;
}
}
/// <summary>
/// Acquires the shared lock.
/// </summary>
public void LockShared() {
lock (m_lock) {
if (!m_exclusive) {
m_locks++;
} else if (m_locks == m_upgrades) {
m_exclusive = false;
m_locks++;
} else {
while (m_exclusive && m_locks > m_upgrades)
Monitor.Wait(m_lock);
m_locks++;
m_exclusive = false;
}
}
}
/// <summary>
/// Upgrades the current lock to exclusive level.
/// </summary>
/// <remarks>If the current lock is exclusive already the method does nothing.</remarks>
public void Upgrade() {
lock (m_lock) {
if (!m_exclusive) {
if (m_locks <= m_upgrades)
throw new InvalidOperationException();
if (m_locks - m_upgrades == 1) {
m_exclusive = true;
} else {
m_upgrades++;
while (m_locks > m_upgrades)
Monitor.Wait(m_lock);
m_upgrades--;
m_exclusive = true;
}
}
}
}
/// <summary>
/// Upgrades the current lock to exclusive level.
/// </summary>
/// <param name="timeout">Timeout.</param>
/// <returns><c>true</c> if the current lock was updated, <c>false</c> the specified timeout was expired.</returns>
/// <remarks>If the current lock is exclusive already the method does nothing.</remarks>
public bool Upgrade(int timeout) {
lock (m_lock) {
if (m_exclusive)
return true;
if (m_locks <= m_upgrades)
throw new InvalidOperationException();
if (m_locks - m_upgrades == 1) {
m_exclusive = true;
} else {
var t1 = Environment.TickCount;
var dt = timeout;
m_upgrades++;
do {
if (!Monitor.Wait(m_lock, dt)) {
m_upgrades--;
return false;
}
// we may get there but the shared lock already aquired
if (m_locks == m_upgrades)
break;
if (timeout >= 0) {
dt = timeout - Environment.TickCount + t1;
if (dt < 0) {
m_upgrades--;
return false;
}
}
} while(true);
m_upgrades--;
m_exclusive = true;
}
return true;
}
}
/// <summary>
/// Downgrades this lock to shared level.
/// </summary>
public void Downgrade() {
lock (m_lock)
m_exclusive = false;
}
/// <summary>
/// Releases the current lock.
/// </summary>
public void Release() {
lock (m_lock)
// if no more running threads left
if (--m_locks == m_upgrades)
Monitor.PulseAll(m_lock);
}
}
}