使用信号量或锁定在c#中使属性线程安全吗?

时间:2014-01-25 10:54:57

标签: c# multithreading locking system.reactive semaphore

我是关于反应的新手,但这个想法让我好奇,所以我做了一个有点反应变量,但我不知道这是不是最好的做法,然后我会把这个线程安全。

这是班级:

 public class RxVar<T>:IObservable<T>
 {

     T _value;
     public T Value
     {

         get{ 
             return _value;
         }
         set{
             if (!_value.Equals(value))
             {
                 onChange(_value);
                 _value = value;
             }
         }

     }


     event onValChange onChange = delegate { };
     delegate void onValChange(T val);

     IObservable<T> _observable;
     public RxVar() {

         _observable = Observable.FromEvent<onValChange,T>(ev => onChange += ev, ev => onChange -= ev);
     }

     public IDisposable Subscribe(IObserver<T> observer)
     {
         return _observable.Subscribe(p=>observer.OnNext(p));
     }
 }

信号量示例

         _semaphoreSlim.WaitOne();
         if (!_value.Equals(value))
         {
             onChange(_value);
             _value = value;
         }
         _semaphoreSlim.release();

好的,我想让这个帖子安全,我害怕死锁。所以, 使用lock或信号量更好,或者由于反应性而不需要它?

感谢。 :)

1 个答案:

答案 0 :(得分:3)

我建议使用锁而不是信号量。对于这种情况,信号量只是错误的工具。

考虑用“return _value”公开实际值意味着即使在getter返回之后,客户端代码也能够修改对象中的数据。所以问题是你在暴露参考后如何避免竞争条件?

答案是不要暴露参考。给出对象/数据的DEEP COPY,而不是原始对象本身。

关于僵局:如果你知道自己在做什么,就不应该害怕。如果你不这样做,你就无法判断永远不会有死锁,因为在每次运行时条件可能会有所不同,即使经过多次成功的测试,你可能会导致死锁并进行调试,这将是一项艰巨的任务

死锁只能通过事先学习来避免,而不是通过任何“不知道编程”的方式来解决。

带锁的小片段:

类实例字段(如果_value可以为null,则需要此项,否则可以锁定_value本身):

private object _valueLock = new Int(0);

在你的方法中:

lock(_valueLock)
{
    if (_value != value) // this or deep equality
    {
        _value = value;
        onChange(this, _value); // for complex Observer-Observable scenarios it's better specifying the observed object
    }
}