C# Cargo cult编程:锁定系统对象

C# Cargo cult编程:锁定系统对象,c#,synchronization,locking,C#,Synchronization,Locking,我想我已经养成了一种货物崇拜编程习惯: 每当我需要使一个类线程安全时,比如一个有字典或列表的类(完全封装:从不直接访问,只由类的成员方法修改),我都会创建两个对象,如下所示: public static class Recorder { private static readonly Object _devicesLock = new Object(); private static readonly Dictionary<String,DeviceRecordings&

我想我已经养成了一种货物崇拜编程习惯:

每当我需要使一个类线程安全时,比如一个有字典或列表的类(完全封装:从不直接访问,只由类的成员方法修改),我都会创建两个对象,如下所示:

public static class Recorder {

    private static readonly Object _devicesLock = new Object();
    private static readonly Dictionary<String,DeviceRecordings> _devices;

    static Recorder() {

        _devices = new Dictionary<String,DeviceRecordings>();

        WaveInCapabilities[] devices = AudioManager.GetInDevices();
        foreach(WaveInCapabilities device in devices) {

            _devices.Add( device.ProductName, new DeviceRecordings( device.ProductName ) );
        }
    }//cctor

    // For now, only support a single device.

    public static DeviceRecordings GetRecordings(String deviceName) {

        lock( _devicesLock ) {

            if( !_devices.ContainsKey( deviceName ) ) {

                return null;
            }

            return _devices[ deviceName ];
        }
    }//GetRecordings
}//class
公共静态类记录器{
私有静态只读对象_devicesLock=新对象();
专用静态只读字典设备;
静态记录器(){
_设备=新字典();
WaveCapabilities[]设备=AudioManager.GetInDevices();
foreach(设备中的设备){
_添加(device.ProductName,新设备记录(device.ProductName));
}
}//cctor
//目前,仅支持单个设备。
公共静态设备录制GetRecordings(字符串deviceName){
锁定(设备锁定){
if(!\u devices.ContainsKey(deviceName)){
返回null;
}
返回设备[deviceName];
}
}//获取录音
}//阶级

在这种情况下,我将
\u设备上的所有操作都封装在
锁(\u devicesLock)中{
block。我开始怀疑这是否必要。为什么我不直接锁定字典?

在您的用例中,锁定字典是可以的,因为它是私有的。您仍然需要仔细设计类以防止死锁


如果字典是唯一需要线程安全的共享资源,并且代码的其他部分是线程安全的,我建议使用,而不是锁定。

如果您确定主对象完全在类中使用,则不需要字典。严格来说,即使是,也不需要字典,但带2变量的版本是much更容易推理:

  • 无论是谁读代码,都不需要考虑主对象是否曾经被您的类之外的东西公开或潜在地锁定
  • 带有单独锁定对象的代码看起来更符合良好实践
  • 如果意外/故意暴露主要对象,则会更安全

当您需要同步变量的初始化时,这通常是必需的。由于此字段是只读的,您可能不需要额外的变量。也就是说,您还没有实际显示初始化
\u设备的位置
+1-值得注意的是,如果字典是完全私有的,只需简单的锁即可完成此任务完成后,它比
ConcurrentDictionary
的引擎盖下发生的事情要简单得多。但是如果需要这一功能,
ConcurrentDictionary
是一个不错的选择。是的,我相信
ConcurrentDictionary
利用
CompareExchange
而不是
监视器。输入
。但是正如你所说的,复杂性是有限的“隐藏”这样至少不会增加代码的维护复杂性(事实上,它可能会降低一点).Performance wise指出,
ConcurrentDictionary
在多核系统上进行高频率读/写时可以显著更快;但是,
Dictionary
在单线程读/写时会更快(在这种情况下,您不需要锁定)。同意,在几乎任何情况下,维护的复杂性都将超过任何性能损失。有趣的MSDN阅读。我已经修改了我的问题,以说明我是如何使用
\u devicesLock
对象的。