【问题标题】:Use SemaphoreSlim in method without exception handling在没有异常处理的方法中使用 SemaphoreSlim
【发布时间】:2016-06-15 14:32:48
【问题描述】:

目前我正在努力实现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 或离开某个术语时始终释放锁?

希望很清楚我在要求/寻找什么。

谢谢大家!

【问题讨论】:

    标签: c# multithreading locking async-await semaphore


    【解决方案1】:

    您可以只使用lock,因为在受保护区域内没有await。这一切都由它来处理。

    如果不是这种情况,您要么需要在任何地方使用 try-finally,要么编写自定义一次性用品,以便您可以使用 using 的作用域性质。

    【讨论】:

    • 我也想过using模式,因为这通常是一种优雅的方式。但是我需要一个异步一次性的,据我所知这是不可能的。非常感谢!
    • 发布是同步的。您可以使用正常的同步处置模式。
    • 谢谢,我试试这个。
    【解决方案2】:

    我建议不要使用lockSemaphoreSlim。相反,使用正确的工具来完成这项工作——在这种情况下,使用ConcurrentDictionary&lt;TKey, Lazy&lt;TValue&gt;&gt; 而不是使用IDictionary&lt;string, string&gt; 以及锁定和信号量似乎更合适。一年前有几篇关于这种模式的文章,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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-02
      • 1970-01-01
      • 2012-02-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-21
      相关资源
      最近更新 更多