Skip to content

Instantly share code, notes, and snippets.

@nillis
Last active August 29, 2015 14:19
Show Gist options
  • Save nillis/0c63930229ac9164ff09 to your computer and use it in GitHub Desktop.
Save nillis/0c63930229ac9164ff09 to your computer and use it in GitHub Desktop.
SingleInstance lock replaced by ReaderWriterLockSlim
/// <summary>
/// Protects shared instances from concurrent access. Other members and the base class are threadsafe.
/// </summary>
readonly ReaderWriterLockSlim _cacheLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
~LifetimeScope()
{
if (_cacheLock != null) _cacheLock.Dispose();
}
/// <summary>
/// Try to retrieve an instance based on a GUID key. If the instance
/// does not exist, invoke <paramref name="creator"/> to create it.
/// </summary>
/// <param name="id">Key to look up.</param>
/// <param name="creator">Creation function.</param>
/// <returns>An instance.</returns>
public object GetOrCreateAndShare(Guid id, Func<object> creator)
{
if (creator == null)
{
throw new ArgumentNullException("creator");
}
object result;
// 1. try to get the shared instance using a read lock which can be acquired by multiple threads
_cacheLock.EnterReadLock();
try
{
if (_sharedInstances.TryGetValue(id, out result))
{
return result;
}
}
finally
{
_cacheLock.ExitReadLock();
}
// 2. when the instance couldn't be fetched, enter the upgradeablereadlock which can be acquired by only one thread
_cacheLock.EnterUpgradeableReadLock();
try
{
if (!_sharedInstances.TryGetValue(id, out result))
{
// 3. when the instance still couldn't be fetched, enter the write lock which also can be acquired by only one thread
_cacheLock.EnterWriteLock();
try
{
result = creator();
_sharedInstances.Add(id, result);
}
finally
{
_cacheLock.ExitWriteLock();
}
}
return result;
}
finally
{
_cacheLock.ExitUpgradeableReadLock();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment