Skip to content

Instantly share code, notes, and snippets.

@hraban
Created March 20, 2012 09:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hraban/2133167 to your computer and use it in GitHub Desktop.
Save hraban/2133167 to your computer and use it in GitHub Desktop.
Custom C# locking interface and implementation
using System;
using System.Threading;
namespace Locking
{
internal interface IWaitableLock
{
/// <summary>
/// Acquire the lock.
/// </summary>
/// <param name="blocking">Whether to wait until acquired or return immediately</param>
/// <returns>true when acquired, false otherwise</returns>
bool Acquire(bool blocking);
/// <summary>
/// Release the lock.
/// </summary>
/// <param name="strict">Whether to assert that the lock is acquired.</param>
/// <exception cref="SynchronizationLockException">
/// Strictly unlocking while already unlocked.
/// </exception>
/// <returns>The state of the lock before this action took place (atomically).</returns>
bool Release(bool strict);
bool IsLocked();
// TODO: These two do not belong here, better use thread-safe queues.
/// <summary>
/// Return as soon as it detects the lock is acquired. Does not affect the lock.
/// </summary>
void WaitWhileUnlocked();
/// <summary>
/// Return as soon as it detects the lock is released. Does not affect the lock.
/// </summary>
void WaitWhileLocked();
/// <summary>
/// Event called after the lock has been acquired
/// </summary>
event Action Acquired;
/// <summary>
/// Event called after the lock has been released
/// </summary>
event Action Released;
}
/// <summary>
/// Simple boolean mutex, like Python's threading.Lock.
/// </summary>
internal class MyLock : IWaitableLock
{
private int locked;
public event Action Acquired = delegate { };
public event Action Released = delegate { };
public MyLock()
{
locked = 0;
}
public bool Acquire(bool wait)
{
if (Interlocked.CompareExchange(ref locked, 1, 0) == 0)
{
Acquired();
return true;
}
else if (wait)
{
WaitWhileLocked();
// The lock was released, try (!) to acquire again.
return Acquire(wait);
}
else
{
return false;
}
}
public bool Release(bool strict)
{
bool waslocked = (Interlocked.CompareExchange(ref locked, 0, 1) == 1);
if (waslocked)
{
Released();
}
else if (strict)
{
throw new SynchronizationLockException("Already unlocked");
}
return waslocked;
}
public bool IsLocked()
{
return locked == 1;
}
public void WaitWhileUnlocked()
{
var wait = new AutoResetEvent(false);
Action set = (() => wait.Set()); // ignore return value
Acquired += set;
try
{
if (locked == 1)
{
return;
}
wait.WaitOne();
}
finally
{
Acquired -= set;
}
}
public void WaitWhileLocked()
{
var wait = new AutoResetEvent(false);
Action set = (() => wait.Set()); // ignore return value
Released += set;
try
{
if (locked == 0)
{
return;
}
wait.WaitOne();
}
finally
{
Released -= set;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment