在没有异常处理的方法中使用SemaphoreSlim
目前,我正在努力实现SemaphoreSlim
,以便锁定必须是线程安全的方法的“部分”。我的问题是,实现这个没有重载异常处理是非常困难的。因为在释放“锁定”之前抛出异常时,它将永远停留在那里。在没有异常处理的方法中使用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
。相反,使用正确的工具进行这项工作 - 在这种情况下,使用IDictionary<string, string>
以及锁定和信号量使用ConcurrentDictionary<TKey, Lazy<TValue>>
似乎是合适的。有一些关于这一年前的文章,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
目标。错误处理按照您的预期进行,假设您的GetSomeValueFromAsyncMethod
函数中存在try/catch
。一些更多的资源:
因为在受保护区域内没有await
,所以您只能使用lock
。这处理所有这一切。
如果不是这种情况,您可能需要在任何地方使用try-finally
或者编写自定义一次性使用,以便您可以使用using
的范围特性。
我也想过'使用'模式,因为这往往是一种优雅的方式。但是,比我需要一个异步一次性,这是不可能的,据我所知。万分感谢! – BendEg
版本是同步的。您可以使用正常的同步处理模式。 – usr
谢谢,我会试试这个。 – BendEg