使用锁根据以前的值修改两个相关字段的最有效方法
本文关键字:两个 方法 有效 字段 修改 | 更新日期: 2023-09-27 18:29:42
我知道使用InterlockedCompareExchange是更快''更好的方法,但如果您仅限于锁定,我只是在寻找最好的方法。
Joe Albahari说:
也可以根据其先前的值安全地分配新的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);
}
}
在您提到的文章中,只需要在一行上进行锁定就是引用了第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);
}
IMO,使用上面的代码,您可以不使用任何锁,因为您使用的是一个不可变的类,并且只能使用数据的副本。C#规范保证读写引用是原子的。
编辑:但是线程同步是一个b***,所以我想听听更多的意见。。。
编辑:正如我在评论中指出的,如果有多个线程调用该方法,则代码中存在缺陷。在这种情况下,更新可能会丢失。