C#中的暂定锁?
假设我希望允许并行执行某些代码,但需要其他代码等待所有这些操作完成 让我们设想一下,除了C#中的暂定锁?,c#,.net,.net-3.5,locking,C#,.net,.net 3.5,Locking,假设我希望允许并行执行某些代码,但需要其他代码等待所有这些操作完成 让我们设想一下,除了锁,还有一个软锁: public static class MySimpleCache { private static readonly SynchronizedCollection<KeyValuePair<string, string>> Collection = new SynchronizedCollection<KeyValuePair<string,
锁
,还有一个软锁
:
public static class MySimpleCache
{
private static readonly SynchronizedCollection<KeyValuePair<string, string>> Collection = new SynchronizedCollection<KeyValuePair<string, string>>();
public static string Get(string key, Func<string> getter)
{
// Allow parallel enumerations here,
// but force modifications to the collections to wait.
softlock(Collection.SyncRoot)
{
if (Collection.Any(kvp => kvp.Key == key))
{
return Collection.First(kvp => kvp.Key == key).Value;
}
}
var data = getter();
// Wait for previous soft-locks before modifying the collection and let subsequent softlocks wait
lock (Collection.SyncRoot)
{
Collection.Add(new KeyValuePair<string, string>(key, data));
}
return data;
}
}
公共静态类MySimpleCache
{
私有静态只读SynchronizedCollection=新SynchronizedCollection();
公共静态字符串Get(字符串键,Func getter)
{
//此处允许并行枚举,
//但强制对集合的修改等待。
软锁(Collection.SyncRoot)
{
if(Collection.Any(kvp=>kvp.Key==Key))
{
返回Collection.First(kvp=>kvp.Key==Key).Value;
}
}
var data=getter();
//在修改集合之前等待以前的软锁,并让后续的软锁等待
锁(Collection.SyncRoot)
{
添加(新的KeyValuePair(key,data));
}
返回数据;
}
}
C#/.NET中是否有任何设计模式或语言/框架特性可以直接可靠地实现这一点,还是必须从头开始实现这一点
我目前只对.NET 3.5感兴趣,我主要对概念问题感兴趣,而不是对其他可能解决这个例子本身的集合感兴趣。在这种情况下,你可以使用,它将允许多个读卡器,直到有人想写,然后它会阻止所有读卡器,只允许一个写卡器通过
public static class MySimpleCache
{
private static readonly SynchronizedCollection<KeyValuePair<string, string>> Collection = new SynchronizedCollection<KeyValuePair<string, string>>();
private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim();
public static string Get(string key, Func<string> getter)
{
//This allows multiple readers to run concurrently.
Lock.EnterReadLock();
try
{
var result = Collection.FirstOrDefault(kvp => kvp.Key == key);
if (!Object.Equals(result, default(KeyValuePair<string, string>)))
{
return result.Value;
}
}
finally
{
Lock.ExitReadLock();
}
var data = getter();
//This blocks all future EnterReadLock(), once all finish it allows the function to continue
Lock.EnterWriteLock();
try
{
Collection.Add(new KeyValuePair<string, string>(key, data));
return data;
}
finally
{
Lock.ExitWriteLock();
}
}
}
p.S.您在评论中提到,该值可能为null,因此
FirstOrDefault()
将不起作用。在这种情况下,使用扩展方法生成TryFirst()
函数
public static class ExtensionMethods
{
public static bool TryFirst<T>(this IEnumerable<T> @this, Func<T, bool> predicate, out T result)
{
foreach (var item in @this)
{
if (predicate(item))
{
result = item;
return true;
}
}
result = default(T);
return false;
}
}
//Used like
Lock.EnterReadLock();
try
{
KeyValuePair<string, string> result;
bool found = Collection.TryFirst(kvp => kvp.Key == key, out result);
if (found)
{
return result.Value;
}
}
finally
{
Lock.ExitReadLock();
}
公共静态类扩展方法
{
公共静态bool TryFirst(this IEnumerable@this,Func谓词,out T result)
{
foreach(@this中的变量项)
{
if(谓语(项))
{
结果=项目;
返回true;
}
}
结果=默认值(T);
返回false;
}
}
//像
Lock.EnterReadLock();
尝试
{
键值对结果;
boolfound=Collection.TryFirst(kvp=>kvp.Key==Key,out结果);
如果(找到)
{
返回结果值;
}
}
最后
{
Lock.exitradelock();
}
在这种情况下,您可以使用,它将允许多个读卡器,直到有人想写,然后它将阻止所有读卡器,并且只允许一个写入器通过
public static class MySimpleCache
{
private static readonly SynchronizedCollection<KeyValuePair<string, string>> Collection = new SynchronizedCollection<KeyValuePair<string, string>>();
private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim();
public static string Get(string key, Func<string> getter)
{
//This allows multiple readers to run concurrently.
Lock.EnterReadLock();
try
{
var result = Collection.FirstOrDefault(kvp => kvp.Key == key);
if (!Object.Equals(result, default(KeyValuePair<string, string>)))
{
return result.Value;
}
}
finally
{
Lock.ExitReadLock();
}
var data = getter();
//This blocks all future EnterReadLock(), once all finish it allows the function to continue
Lock.EnterWriteLock();
try
{
Collection.Add(new KeyValuePair<string, string>(key, data));
return data;
}
finally
{
Lock.ExitWriteLock();
}
}
}
p.S.您在评论中提到,该值可能为null,因此
FirstOrDefault()
将不起作用。在这种情况下,使用扩展方法生成TryFirst()
函数
public static class ExtensionMethods
{
public static bool TryFirst<T>(this IEnumerable<T> @this, Func<T, bool> predicate, out T result)
{
foreach (var item in @this)
{
if (predicate(item))
{
result = item;
return true;
}
}
result = default(T);
return false;
}
}
//Used like
Lock.EnterReadLock();
try
{
KeyValuePair<string, string> result;
bool found = Collection.TryFirst(kvp => kvp.Key == key, out result);
if (found)
{
return result.Value;
}
}
finally
{
Lock.ExitReadLock();
}
公共静态类扩展方法
{
公共静态bool TryFirst(this IEnumerable@this,Func谓词,out T result)
{
foreach(@this中的变量项)
{
if(谓语(项))
{
结果=项目;
返回true;
}
}
结果=默认值(T);
返回false;
}
}
//像
Lock.EnterReadLock();
尝试
{
键值对结果;
boolfound=Collection.TryFirst(kvp=>kvp.Key==Key,out结果);
如果(找到)
{
返回结果值;
}
}
最后
{
Lock.exitradelock();
}
听起来像是您需要的,它可以从读卡器锁开始,升级到写器锁。您的查找效率稍低,您可以枚举两次,您可以使用var result=Collection.FirstOrDefault(kvp=>kvp.Key==Key);如果(result!=default(KeyValuePair)){return result.Value;}
并且只查找一次。@MatthewWatson谢谢,这看起来非常合适,我将使用它。哎呀!=不起作用,但我正在编写一个答案(使用ReaderWriterLockSlim),该答案也将有一个固定版本。@ScottChamberlain,但我通常无法区分集合是否不包含该值,或者它包含的值是否为null。听起来您需要一个从读卡器锁开始的答案,您的查找效率稍低,枚举两次,可以使用var result=Collection.FirstOrDefault(kvp=>kvp.Key==Key);如果(result!=default(KeyValuePair)){return result.Value;}
并且只查找一次。@MatthewWatson谢谢,这看起来非常合适,我将使用它。哎呀!=不起作用,但我正在编写一个答案(使用ReaderWriterLockSlim),该答案也将有一个固定版本。@ScottChamberlain,不过我通常无法区分集合是否不包含该值,或者它包含的值是否为null。