在没有异常处理的方法中使用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或某个术语离开时,总是可以释放锁吗?

希望很清楚我在问什么。

谢谢大家!

我建议不是使用lockSemaphoreSlim。相反,使用正确的工具进行这项工作 - 在这种情况下,使用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。一些更多的资源:

最后,我创建an example .NET fiddle to help demonstrate the idea

因为在受保护区域内没有await,所以您只能使用lock。这处理所有这一切。

如果不是这种情况,您可能需要在任何地方使用try-finally或者编写自定义一次性使用,以便您可以使用using的范围特性。

+0

我也想过'使用'模式,因为这往往是一种优雅的方式。但是,比我需要一个异步一次性,这是不可能的,据我所知。万分感谢! – BendEg

+0

版本是同步的。您可以使用正常的同步处理模式。 – usr

+0

谢谢,我会试试这个。 – BendEg