SharedLock.cs
202 lines
| 6.3 KiB
| text/x-csharp
|
CSharpLexer
cin
|
r129 | 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(); | ||||
cin
|
r136 | // the count of locks currently acquired by clients | ||
cin
|
r129 | int m_locks; | ||
cin
|
r136 | // the count of pending requests for upgrade | ||
int m_upgrades; | ||||
cin
|
r129 | bool m_exclusive; | ||
public bool LockExclusive(int timeout) { | ||||
lock (m_lock) { | ||||
cin
|
r136 | 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); | ||||
} | ||||
cin
|
r129 | m_exclusive = true; | ||
cin
|
r136 | m_locks ++; | ||
cin
|
r130 | return true; | ||
cin
|
r129 | } | ||
} | ||||
public void LockExclusive() { | ||||
cin
|
r136 | lock (m_lock) { | ||
while (m_locks > m_upgrades) | ||||
Monitor.Wait(m_lock); | ||||
m_exclusive = true; | ||||
m_locks ++; | ||||
} | ||||
cin
|
r129 | } | ||
cin
|
r136 | /// <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> | ||||
cin
|
r129 | public bool LockShared(int timeout) { | ||
lock (m_lock) { | ||||
if (!m_exclusive) { | ||||
m_locks++; | ||||
return true; | ||||
} | ||||
cin
|
r136 | if (m_locks == m_upgrades) { | ||
cin
|
r129 | m_exclusive = false; | ||
m_locks = 1; | ||||
return true; | ||||
} | ||||
cin
|
r136 | |||
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) { | ||||
cin
|
r129 | m_exclusive = false; | ||
cin
|
r136 | m_locks++; | ||
} else { | ||||
while (m_exclusive && m_locks > m_upgrades) | ||||
Monitor.Wait(m_lock); | ||||
m_locks++; | ||||
m_exclusive = false; | ||||
cin
|
r129 | } | ||
} | ||||
} | ||||
cin
|
r136 | /// <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() { | ||||
cin
|
r129 | lock (m_lock) { | ||
cin
|
r136 | 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; | ||||
} | ||||
} | ||||
cin
|
r129 | } | ||
} | ||||
cin
|
r136 | /// <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) { | ||||
cin
|
r129 | lock (m_lock) { | ||
cin
|
r136 | if (m_exclusive) | ||
return true; | ||||
if (m_locks <= m_upgrades) | ||||
cin
|
r129 | throw new InvalidOperationException(); | ||
cin
|
r136 | |||
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; | ||||
cin
|
r129 | } | ||
} | ||||
cin
|
r136 | /// <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); | ||||
} | ||||
cin
|
r129 | } | ||
} | ||||