【问题标题】:Handling concurrency issues on multithreaded service处理多线程服务的并发问题
【发布时间】:2019-02-07 11:25:23
【问题描述】:

我正在设计一个具有一些静态字典(即维护服务器和连接的客户端的某些状态)的 Web 服务 (wcf)。服务为单实例模式,多并发,如下图。

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Multiple)]   
public class CalculatorService : ICalculatorConcurrency   
{   
    ...  
}  

有多种操作可以读取和写入此静态变量。我有一个类级别的锁定对象,我试图避免锁定的方法是在任何操作尝试访问该特定静态变量时使用该对象。

我是否正确处理了并发,如下所示?可以有客户端访问服务的各种实例,即

  • Client1 使用服务来 modify() 字典
  • Client2 使用服务来清除()字典
  • Client3 使用服务读取()字典

示例代码如下:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Multiple)]
    public class CalculatorService : ICalculatorConcurrency
    {   
        private static int clientId;
        private static object lockObject = new object();
        private static Dictionary<int, Number> numberList = new Dictionary<int, Number>();


    public static Number ReadNumber(int n)
    {
        Number info;
        lock (lockObject)
        {
            if (!numberList.TryGetValue(n, out info))
            ...
        }
    }

    public static bool Modify(Number number)
    {
        lock (lockObject)
        {
            ...
        }
    }

    public bool Clear()
    {
        lock (lockObject)
        {
            numberList.Clear();
            ...
        }               
    }
}

我的代码线程安全吗?或者,我做对了吗?

【问题讨论】:

  • 你运行了吗?发生了什么?
  • @jsanalytics 它按预期运行,但我不确定这是否足以解决可能的死锁?另外,如果我对每种方法使用不同的锁定对象,是否会有所不同,因为我没有注意到结果有任何变化?
  • 您是否运行过包含多个任务同时多次调用您的服务的场景?
  • @jsanalytics 我不太熟悉如何从实际服务中调试这些并发问题,因此希望您能提供一些见解,我将不胜感激。对于我的测试,我从不同的测试应用程序调用了相同的服务:控制台应用程序和桌面应用程序

标签: multithreading wcf concurrency locking deadlock


【解决方案1】:

由于您只使用一种资源(即lockObject),死锁是不可能的。要获得死锁,您需要至少有两个资源。

我的代码线程安全吗?

如果您使用Dictionary&lt;,&gt; 来避免任何并发问题,则与该字典的每次交互都应像您一样由lock(lockObject){} 包装。所以,你的代码是线程安全的。

我做得对吗?

您做得正确,但如果您使用.Net 4 或最新版本,您可以使用线程安全ConcurrentDictionary&lt;TKey,TValue&gt; 更方便的选项。它专为像您这样的情况而设计。不同之处在于您可以忘记lock 块。当一个调用者遍历字典并且第二个调用者更改字典时,它不会抛出异常。 ConcurrentDictionary&lt;TKey,TValue&gt;实现了IDictionary&lt;TKey,TValue&gt;,另外还提供了TryAddTryUpdate等方便的方法。

所以,如果可能的话,你肯定需要使用ConcurrentDictionary,因为它使代码更简洁。

【讨论】:

  • 感谢您的回复和其他见解。我将探索并发类型
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-14
  • 2020-09-25
  • 2021-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多