我有一个表示日期库中的表的类,该类的每个属性都映射到数据库中的列。这个类现在有几个属性,实际上是57个。我需要在几个线程之间共享这些设备的列表。
我的第一个问题是我应该使用哪种类型的集合,最好像在线程之间共享的列表。从查看System.Collections.Concurrent命名空间,我相信ConcurrentBag最适合我的需要,但如果有任何其他建议,我愿意接受它。
其次,分配给我的班级属性的值会随着时间而改变。我已经看到了将锁定放在属性的get和set块中的示例,但我想知道是否有一种更清晰的方法,而不是声明57个不同的锁定变量并将锁定全部放在我的代码中。
答案 0 :(得分:3)
首先,如果您关注并发访问,您可能需要考虑针对整个类为lock
制作单个对象,从而导致“任何更改需要具有独占访问权限”行为。这取决于每次写入等待单次写入的性能命中率,以及不同属性一次更改或依赖于彼此值的频率。
另一种解决方案是编写一个包装器类型,并为每个底层private *** _value
字段将它包装在所述包装器中,该包装器可以处理每个对象的单锁,允许最少的代码重复,具有相同的重复性能。但是,这将要求每个属性都有一个显式的主体和底层字段,而不是让编译器完成工作,所以要注意这种权衡。还要注意,通过使用它将它包装在class
中可以巧妙地改变值类型的一些行为,尽管像这样的简单传入传递不应该看到任何这样的效果。
class ConcurrencyWrapper<T>
{
priavte object _lockObject = new object();
private T _value;
public T Value
{
get { lock(_lockObject) return _value; }
set { lock(_lockObject) _value = value; }
}
}
正如@Patrick Hofman所指出的那样(参见评论),您还可以使用可锁定对象的字典,并通过CallerMemberNameAttribute
根据每个属性的名称访问它们。private ConcurrentDictionary<string, object> lockDict = new ConcurrentDictionary<string, object>();
private object GetLock([CallerMemberName] string name)
{
return lockDict.GetOrAdd(name,
(key) => new object()); // Using a lambda here prevents evaluation each time the dictionary is queried
}
...
private string _someProperty;
public string SomeProperty
{
get { lock(GetLock()) return _someProperty; }
set { lock(GetLock()) _someProperty = value; }
}
最后,如果你有很多并发读访问但只有少量写操作,请查看ReaderWriterLockSlim class,因为这允许并发读取但是单个写入。请注意,这需要比lock(_lockObject)
更详细,因为您需要自己执行整个try { } catch { } finally { }
设置。