SharedLock.cs
201 lines
| 6.3 KiB
| text/x-csharp
|
CSharpLexer
cin
|
r289 | using System; | ||
using System.Threading; | ||||
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); | ||||
} | ||||
} | ||||
} | ||||