最有效的方法是使用锁来根据以前的值修改两个相关字段?

时间:2012-04-01 02:27:37

标签: c# .net clr4.0

我知道他们使用Interlocked.CompareExchange是更快\更好的方法,但我只是在寻找最好的方法,如果你只限于锁。

Joe Albahari says the following:

  

还可以根据其先前的值安全地分配新的ProgressStatus对象(例如,可以“递增”PercentComplete值) - 而不会锁定多行代码。

编辑:根据@ drch的答案更新了代码。等待看看是否有办法用更小\更有效的锁来做到这一点。此锁具有锁定中的读取,写入和新构造函数。希望有一个更小的\更有效的锁。感谢。

class ProgressStatus
{
    public readonly int PercentComplete;
    public readonly string StatusMessage;
    public ProgressStatus(int percentComplete, string statusMessage)
    {
        PercentComplete = percentComplete;
        StatusMessage = statusMessage;
    }
}
class Test
{
    readonly object _statusLocker = new object();
    ProgressStatus _status;
    void IncreaseProgress()
    {
        lock (_statusLocker)
          _status = new ProgressStatus(_status.PercentComplete + 10, _status.StatusMessage);
    }
}

2 个答案:

答案 0 :(得分:1)

在您提到的文章中,只需要在一行上锁定就引用了Part 5中的高级技术。

关于上面的代码,可以在两个锁之间获得竞争条件。两个线程可以读取相同的值,然后在所需的结果使它们都递增时写入相同的值。

锁定整个读写:

lock (_statusLocker) {
    statusCopy = _status;
    var newStatus = new ProgressStatus(statusCopy.PercentComplete + 10, statusCopy.StatusMessage);
    _status = newStatus;
}

或者简单地说:

lock (_statusLocker) {
   _status = new ProgressStatus(_status.PercentComplete + 10, _status.StatusMessage);
}

答案 1 :(得分:0)

IMO,使用上面的代码,您可以不使用任何锁,因为您使用的是不可变类,并且只处理数据副本。读取和写入引用保证是C#规范的原子。

编辑但是线程同步是一个b ***,所以我想听一些更多的意见......

编辑:正如我在评论中指出的那样,如果有多个线程调用该方法,则代码中存在缺陷。在这种情况下,更新可能会丢失。