1

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

乔阿尔巴哈里说:

还可以安全地根据其先前的值分配一个新的 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);
    }
}
4

2 回答 2

1

在您提到的文章中,仅需要锁定一行是在第 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);
}
于 2012-04-01T04:08:07.223 回答
0

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

编辑:但是线程同步是ab***,所以我想听听更多意见......

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

于 2012-04-01T02:35:29.610 回答