我可以使用联锁操作来更新多个值以避免锁定关键部分/互斥锁吗?

Posted

技术标签:

【中文标题】我可以使用联锁操作来更新多个值以避免锁定关键部分/互斥锁吗?【英文标题】:Can I use interlocked operations to update multiple values to avoid locking a critical section/mutex? 【发布时间】:2009-06-11 20:01:57 【问题描述】:

我有一个多线程应用程序 (C++),我需要在其中增加/更改一系列值。 如果我使用一系列互锁操作,它们是否被视为单个原子操作?就像在这个例子中一样:

InterlockedIncrement(&value1);
InterlockedIncrement(&value2);
InterlockedExchange(&oldValue, newValue);

或者对我们来说最好是一个锁来执行同步?像这样:

EnterCriticalSection(&cs);
value1++;
value2++;
oldValue = newValue;
LeaveCriticalSection(&cs);

我认为锁是必需的,但我不确定……所有值要么处于旧状态,要么处于新状态,这一点非常重要。

【问题讨论】:

【参考方案1】:

InterlockedIncrement 本身是一个原子操作,但一系列InterLockedIncrement 在一起不是原子的。如果您的要求是获得一系列操作的原子性,那么您可以使用临界区。

【讨论】:

补充一点,不要直接使用 EnterCriticalSection 和 LeaveCriticalSection,因为在异常情况下可能不会调用 LeaveCriticalSection。因此,请使用 CSingleLock 类,它会自动为您锁定和解锁关键部分。【参考方案2】:

如果必须完全执行这些值才能保持一致状态,则需要使用临界区。例如,如果您的价值观实际上类似于

   President = Barack Obama;
   VP = Joe Biden;

并且您没有使用关键部分,如果您在执行这些语句之间存在某种中断或上下文切换,您可能会处于巴拉克奥巴马被任命为总统而迪克切尼是副总裁的情况。这种状态是不一致的,我想我们都会同意 :)

但是,如果你正在做类似的事情

   Debit $5 from account;
   Credit $2 to account;

并且每次操作的结果都留下一个完整的状态,联锁就可以了。

【讨论】:

【参考方案3】:

你应该使用临界区来确保原子性。

【讨论】:

【参考方案4】:

您必须定义“状态”是什么。看起来您希望所有三个变量都以原子方式更改 - 在这种情况下,三个单独的原子是不够的。但是如果你可以将所有状态组合成某种对象,你应该能够使用“交换指针”技术来更新状态。

【讨论】:

【参考方案5】:

您是对的,因为所有值要么处于旧状态,要么处于新状态;你应该使用临界区

【讨论】:

以上是关于我可以使用联锁操作来更新多个值以避免锁定关键部分/互斥锁吗?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL伪事务和性能

在析构函数中锁定和解锁关键部分以避免崩溃是正确的方法吗?

关键部分 - 只有单线程在锁定时“休眠”

Spring data jpa 插入多个表以避免锁定表

Django-Channels:在课堂上锁定关键部分

死锁产生的原因及避免死锁的方法