【问题标题】:Incorrect use of InterlockedCompareExchange to copy a value atomically?错误地使用 InterlockedCompareExchange 以原子方式复制值?
【发布时间】:2018-10-11 14:12:31
【问题描述】:

我不能在这里使用 C++11 原子

我对使用InterlockedCompareExchange() 来“原子地”读取变量存有疑问。

我问了一个关于这个here 的问题,但我在那里做的事情不同。 “exchange”和“comperand”参数(第 2 个和第 3 个)是“硬编码”值,即不是从变量中读取的。

请考虑一下:

    // Copy the connect time
    DWORD dwConnectTime = InterlockedCompareExchange(&msgInfo.m_dwConnectTime, 
                            msgInfo.m_dwConnectTime, 
                            msgInfo.m_dwConnectTime);

这旨在将msgInfo.m_dwConnectTime 的值与msgInfo.m_dwConnectTime 的当前值交换,前提是msgInfo.m_dwConnectTime 的当前值是msgInfo.m_dwConnectTime。然后返回之前的 msgInfo.m_dwConnectTime 值,这是我用来“复制”该值的依据。

我刚刚意识到msgInfo.m_dwConnectTime 的第二个和第三个参数本身的读取并不能保证是原子的。因此,这段代码是否不正确,因此我需要使用锁定原语来复制msgInfo.m_dwConnectTime?

【问题讨论】:

标签: c multithreading winapi


【解决方案1】:

根据 cmets 和您之前问题的链接,这个问题的动机是您希望避免撕裂。读取和写入对齐的数据是原子的。您正试图防止撕裂,但当数据对齐时,撕裂是不可能的。并且可以合理地假设您的数据是对齐的,因为这是 InterlockedCompareExchange 以及所有 InterlockedXXX 函数的要求。

因此,您提出的问题是不合逻辑的。它基于一个错误的前提,即对齐的数据可能会发生撕裂。

因此,您无需调用InterlockedCompareExchange 或任何其他InterlockedXXX 函数来避免撕裂,因为只有在数据未对齐时才能进行撕裂。

【讨论】:

  • 好的,那么如果线程 A 读取和线程 B 写入(都在不同的内核上运行)绝对,精确地同时会发生什么。那里肯定有撕裂的可能吗?否则如何确定哪个先行? LOCK 不就是为了防止其他人访问该内存吗?如果这不能发生,那我们为什么需要LOCK?
  • @Wad 线程 读取旧值或新值。但是原子的。请注意,我们不尝试更改,而只尝试读取。
  • 也许你不知道什么是撕裂?撕裂是您拥有跨越缓存行的数据的地方。为了读取或写入它,执行两个内存操作,一个在高速缓存行边界的两侧。如果两个读取操作与两个写入操作交错,那么您将获得部分读取。那是撕裂。但是,对于对齐的数据,内存都在单个高速缓存行中,并且读取和写入由内存总线串行化。它们可以以不可预知的顺序发生,但它们永远不会撕裂。
  • 对。好的。我已经读过几次了,很明显我不知道什么是撕裂。感谢您的澄清。 “读取和写入由内存总线序列化” - 这是一个专门针对我的答案,询问如果读取和写入完全相同会发生什么?换句话说,它们不能同时发生?
  • 没错。虽然两个处理器可能同时读取和写入指令到同一个高速缓存行,但在执行这些指令时,内存总线会确保它们一次发生一个。
猜你喜欢
  • 2011-06-09
  • 2021-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多