通常,当我想一类是线程安全的,我这样做如下:这是一个很好的设计在C#中创建线程安全类?
public class ThreadSafeClass
{
private readonly object theLock = new object();
private double propertyA;
public double PropertyA
{
get
{
lock (theLock)
{
return propertyA;
}
}
set
{
lock (theLock)
{
propertyA = value;
}
}
}
private double propertyB;
public double PropertyB
{
get
{
lock (theLock)
{
return propertyB;
}
}
set
{
lock (theLock)
{
propertyB = value;
}
}
}
public void SomeMethod()
{
lock (theLock)
{
PropertyA = 2.0 * PropertyB;
}
}
}
它的工作原理,但它是非常冗长。有时我甚至会为每种方法和属性创建一个锁对象,以创建更多的冗长和复杂性。
我知道也可以使用Synchronization属性来锁定类,但我不确定这个比例有多好 - 因为我经常期望有数十万甚至数百万个线程安全实例对象。这种方法会为类的每个实例创建一个同步上下文,并且要求该类从ContextBoundObject派生,因此不能从其他任何派生出来 - 因为C#不允许多继承 - 这是一个显示限制器在许多情况下。
编辑:正如几位响应者所强调的那样,没有“银弹”线程安全的类设计。我只是想了解我使用的模式是否是最好的解决方案之一。当然,在任何特定情况下的最佳解决方案都依赖于问题。以下几个答案包含应考虑的替代设计。
编辑:此外,有多个线程安全的定义。例如,在上面我的实现,下面的代码不会是线程安全的:
var myObject = new ThreadSafeClass();
myObject.PropertyA++; // NOT thread-safe
因此,没有上面的类定义代表了一个好办法?如果不是,那么对于具有类似行为的设计,您会推荐哪种设计,这些设计对于类似的用途是线程安全的?
请先搜索:http://stackoverflow.com/search?q=What+is+the+Best+Practice+for+Creating+Thread-Safe+Classes+in+C%23 – 2010-01-25 20:06:33
嗯。在你的代码中,你使用相同的锁对象来读取PropertyA和PropertyB。这意味着一个读取PropertyA的线程会锁定另一个尝试读取PropertyB的内容,直到第一个线程完成。那是你要的吗?如果这是我的课程,我会为每个吸气器创建一个单独的读取锁定器,然后设置者也必须尊重该锁定。请参阅下面的答案。 – 2010-01-25 20:44:48
我只是低估了你,因为没有单一的方法来产生一个线程安全的类。对这个问题的任何回答都有可能给未来的读者带来错误的印象。 – 2010-01-26 01:06:09