处理多线程服务的并发问题
Handling concurrency issues on multithreaded service
我正在设计一个 Web 服务 (wcf),其中包含一些静态字典(即维护服务器和连接的客户端的某些状态)。服务为单实例模式,多并发,如下图
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Multiple)]
public class CalculatorService : ICalculatorConcurrency
{
...
}
有多种读取和写入此静态变量的操作。我有一个 class 级别的锁对象,我试图避免锁的方法是在任何操作试图访问该特定静态变量时使用该对象。
我是否正确处理并发,如下所示?可以有客户端访问服务的各种实例,即
- Client1 使用服务修改()字典
- Client2 使用 clear() 字典服务
- Client3 使用 read() 字典服务
示例代码如下所示:
[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();
...
}
}
}
我的代码线程安全吗?或者,而且我做得对吗?
由于您只使用一种资源(即 lockObject
),因此不可能出现死锁。要获得死锁,您需要至少有两个资源。
Is my code thread safe?
如果您使用 Dictionary<,>
来避免任何并发问题,则与该词典的每次交互都应像您所做的那样由 lock(lockObject){}
包装。所以,你的代码是线程安全的。
Am I doing it correctly?
你做得对,但如果你使用的是 .Net 4
或最新的,你有更方便的线程安全选项 ConcurrentDictionary<TKey,TValue>
。它专为像您这样的情况而设计。不同之处在于您可以忘记 lock
个块。当一个调用者遍历字典而第二个调用者更改字典时,它不会抛出异常。 ConcurrentDictionary<TKey,TValue>
实现了 IDictionary<TKey,TValue>
,此外,还提供了方便的方法,如 TryAdd
、TryUpdate
和其他。
因此,如果可能的话,您绝对需要使用 ConcurrentDictionary
,因为它使代码更简洁。
我正在设计一个 Web 服务 (wcf),其中包含一些静态字典(即维护服务器和连接的客户端的某些状态)。服务为单实例模式,多并发,如下图
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Multiple)]
public class CalculatorService : ICalculatorConcurrency
{
...
}
有多种读取和写入此静态变量的操作。我有一个 class 级别的锁对象,我试图避免锁的方法是在任何操作试图访问该特定静态变量时使用该对象。
我是否正确处理并发,如下所示?可以有客户端访问服务的各种实例,即
- Client1 使用服务修改()字典
- Client2 使用 clear() 字典服务
- Client3 使用 read() 字典服务
示例代码如下所示:
[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();
...
}
}
}
我的代码线程安全吗?或者,而且我做得对吗?
由于您只使用一种资源(即 lockObject
),因此不可能出现死锁。要获得死锁,您需要至少有两个资源。
Is my code thread safe?
如果您使用 Dictionary<,>
来避免任何并发问题,则与该词典的每次交互都应像您所做的那样由 lock(lockObject){}
包装。所以,你的代码是线程安全的。
Am I doing it correctly?
你做得对,但如果你使用的是 .Net 4
或最新的,你有更方便的线程安全选项 ConcurrentDictionary<TKey,TValue>
。它专为像您这样的情况而设计。不同之处在于您可以忘记 lock
个块。当一个调用者遍历字典而第二个调用者更改字典时,它不会抛出异常。 ConcurrentDictionary<TKey,TValue>
实现了 IDictionary<TKey,TValue>
,此外,还提供了方便的方法,如 TryAdd
、TryUpdate
和其他。
因此,如果可能的话,您绝对需要使用 ConcurrentDictionary
,因为它使代码更简洁。