目前我正在努力实现 SemaphoreSlim
用于“锁定”必须是线程安全的方法的“部分”。我的问题是,在没有重载异常处理的情况下实现这一点非常困难。因为当在释放“锁”之前抛出异常时,它会永远留在那里。
这是一个例子:
private SemaphoreSlim _syncLock = new SemaphoreSlim(1);
private IDictionary<string, string> dict = new Dictionary<string, string>();
public async Task ProcessSomeThing(string input)
{
string someValue = await GetSomeValueFromAsyncMethod(input);
await _syncLock.WaitAsync();
dict.Add(input, someValue);
_syncLock.Release();
}
如果输入多次具有相同的值,此方法将引发异常,因为具有相同键的项目将被添加到字典中两次,并且“锁”不会被释放。
假设我有很多 _syncLock.Release();
和_syncLock.Release();
,很难写出try-catch
或.ContainsKey
或者是其他东西。这会完全破坏代码......是否可以在 Exception
时始终释放锁?被抛出或某些术语被留下?
希望我的要求/渴望是什么很清楚。
谢谢大家!
最佳答案
我建议不要使用lock
或SemaphoreSlim
。相反,使用正确的工具来完成工作 - 在这种情况下,使用 ConcurrentDictionary<TKey, Lazy<TValue>>
似乎是合适的。过度使用 IDictionary<string, string>
以及锁定和信号量。一年前已经有几篇关于这种模式的文章,here's one of the them 。因此,遵循这个建议的模式将如下所示:
private ConcurrentDictionary<string, Lazy<Task<string>>> dict =
new ConcurrentDictionary<string, Lazy<Task<string>>>();
public Task ProcessSomeThing(string input)
{
return dict.AddOrUpdate(
input,
key => new Lazy<Task<string>>(() =>
GetSomeValueFromAsyncMethod(key),
LazyThreadSafetyMode.ExecutionAndPublication),
(key, existingValue) => new Lazy<Task<string>>(() =>
GetSomeValueFromAsyncMethod(key), // unless you want the old value
LazyThreadSafetyMode.ExecutionAndPublication)).Value;
}
最终这实现了 asynchronously
的线程安全目标添加到您的dictionary
。错误处理按照您的预期发生,假设有 try / catch
在你的GetSomeValueFromAsyncMethod
功能。更多资源:
- Why does ConcurrentDictionary.GetOrAdd(key, valueFactory) allow the valueFactory to be invoked twice?
- http://softwareblog.alcedo.com/post/2012/01/11/Sometimes-being-Lazy-is-a-good-thing.aspx
最后,我创建了an example .NET fiddle to help demonstrate the idea .
关于c# - 在方法中使用SemaphoreSlim而不进行异常处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35752306/