lock vs Interlocked.Exchange

时间:2015-08-20 14:58:25

标签: c# multithreading locking task interlocked

我有一个应用程序,它不断地(+ -100ms)从PLC读取订单,然后将它们放入一个模型中,然后由多个客户端读取。 对于这个我使用锁定语句。

订单阅读主题:

lock (model) {
//update object
}

客户阅读:

lock (model) {
//serialize object to json string
}
send over tcp stream to client.

但我也可以用于更新:

Interlocked.ExChange(oldObj, newObj)

我不希望我的客户必须等待订单阅读线程中发生的锁定。 我绝对不希望客户阻止我的订单阅读线程。

我最好使用Interlocked吗?

感谢您的建议!

2 个答案:

答案 0 :(得分:3)

是的,您最好使用Interlocked,因为它更有效率,因为它主要转换为单个原子操作。

但是,如果您不介意客户端仍然只读取旧对​​象,您甚至可以在没有Interlocked的情况下进行操作,只需设置一个新实例。

碰巧获得新实例的客户将获得更新的数据,而那些不会在下一次检查中获得的数据。

答案 1 :(得分:1)

如果您的单个制作人正在创建一个全新的模型,并将其分配到共享字段,那么是Interlocked.Exchange就是这里的方式。

如果您的制作人不需要知道模型是什么,那么您可以使用Volatile.Write(ref _sharedObj, newObj)来保持简单。

请注意以下三点:

  1. 使用Volatile.Read阅读您的共享对象。
  2. 消费者应该在每个工作单元

    中读取共享状态一次
    //incorrect - _sharedObj is not guaranteed to be the same in both reads
    var x = CalculateX(_sharedObj);
    var y = CalculateY(_sharedObj);
    
    //correct
    var obj = Volatile.Read(ref _sharedObj);
    var x = CalculateX(obj);
    var y = CalculateY(obj);
    
  3. 消费者有时会使用略显过时的模型。因此,请确保使用稍微过时的对象不会给您带来任何麻烦

    var obj = _sharedObj;
    // If _sharedObj is exchanged here, then `obj` will be outdated
    var x = CalculateX(obj);
    var y = CalculateY(obj);