在 C++ 中将值从 X 更改为 X 会导致数据竞争吗?

Posted

技术标签:

【中文标题】在 C++ 中将值从 X 更改为 X 会导致数据竞争吗?【英文标题】:Can changing a value from X to X in C++ lead to a data race? 【发布时间】:2021-06-14 09:30:09 【问题描述】:

我的代码适用于具有不同布局的大型数据块。布局会决定哪些部分数据是固定的,哪些数据是不固定的。一旦数据被固定在一个块中,它通常就不会再改变了。所以所有的代码读取数据总是会看到相同的数据。

但是,其他服务可以在这些块中进行更改,只要它们确定没有代码会读取块的那部分。为了简化代码,包含更改的块将从一个服务发送到另一个服务,而不管块的布局如何。然后接收服务将覆盖整个块,包括未更改的数据。让我用一个例子来说明这一点:

假设我们有以下数据块:

57 23 98 17 25 00 00 00 00 00

假设前 5 个值是“固定的”。我们服务中的代码只会读取前 5 个值,而不会读取接下来的 5 个值。由于我们的架构设计,我们可以保证这一点。接下来的 5 个值实际上没有意义,所以我在表中填了零来说明这一点。

现在另一个服务确定接下来的 5 个值,将完整的块发送到我们的服务,我们只需用新数据覆盖完整的块。由于前 5 个值是“固定的”,它们保持不变,但传输和覆盖块的代码不知道块的布局,所以它唯一能做的就是覆盖整个块。结果如下:

57 23 98 17 25 08 33 42 71 85

如前所述,前 5 个值没有改变,尽管它们被传输逻辑覆盖。

问题是:这是一场数据竞赛吗?如果其他线程可以同时读取数据,是否允许用完全相同的值覆盖内存地址?

【问题讨论】:

我喜欢你的问题,认为它很清楚,不知道我是否可以回答.....但是,请记住,*** 的用户喜欢查看代码。也许您可以模拟一些代码来说明您描述的活动。使用慷慨的评论来表达隐含或特殊之处。 我假设我们正在查看普通内存。没有像内存映射外设或 DMA 处理的区域......请确认或详细说明。 @Yunnosch 即使有这样的影响——因为源和目标无论如何都是相同的,即使是对值的破坏读取不能导致数据不一致,所以除非标准规定这是UB,我认为没有问题。然而,changed 部分需要被保护。但是,如果不知道哪个部分需要保护,应对代码应该如何做到这一点?如果它知道,它可以简单地跳过不需要的部分...... @Aconcagua 你似乎生活/工作在一个比我更受保护的世界里。如果您从未遇到硬件正在写入一个字节/寄存器会更改从另一个字节读取的值 - 然后认为自己很高兴。我在这里说的是非常奇怪的硬件。并且只要求确认,因为我了解到偏执狂对于(嵌入式)程序员来说是一种健康的心态。 @Yunnosch 好点 - 默默地假设这是普通 RAM,没有注意到映射到内存地址空间的功能寄存器也可能在这里涉及...... 【参考方案1】:

这是一场数据竞赛吗?

是的。

如果其他线程可以同时读取数据,是否允许用完全相同的值覆盖内存地址?

没有明确说明 - 这也不是唯一的问题。

如果您的编译器实际上执行单个 8 字节加载,那么您在最后 3 个字节上存在真实(即,甚至可能不仅仅是理论上的)数据竞争。假设您有一台假设机器,其中uint64_t57 23 98 17 25 00 00 42 是一个陷阱表示,您的更新线程使用memmove,并且它复制更新向后

然而,数据竞争意味着行为是未定义的标准。它可能在特定平台上定义良好 - 例如任何没有整数陷阱表示的平台、任何您知道编译器将真正使用字节加载的平台,或任何具有幂等存储明确语义的平台。

例如,请参阅[intro.races] note 23:

引入对潜在共享内存位置的推测性读取的转换可能不会保留本文档中定义的 C++ 程序的语义,因为它们可能会引入数据竞争。 但是,它们通常在针对具有明确定义的数据竞争语义的特定机器的优化编译器的上下文中有效。 它们对于不容忍竞争或提供硬件竞争检测的假设机器无效

(对于非投机性竞赛没有这样的说明,对于您的幂等存储也没有特别的例外,但在 IMO 采用相同的方法是合理的)。

显然,如果您可以编写代码,使其依赖于这些平台细节,那么在面对编译器和/或平台更新时,它将更便携且不易损坏。只是在块的两个版本之间进行原子交换(因此您从保证不变的副本读取,并写入保证不共享的副本)将始终正确,并且由于减少缓存/一致性流量甚至可能更快。

【讨论】:

【参考方案2】:

有太多“取决于”,无法用明确的陈述来回答这个问题。

如果这个结构是一些生产性代码的一部分,那么答案是:肯定是的。可能会出现竞争条件。必须使用任务同步机制。无法进行讨论。

【讨论】:

以上是关于在 C++ 中将值从 X 更改为 X 会导致数据竞争吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何防止在 Python matplotlib 图中将数字更改为指数形式

Ruby .store 函数将哈希值从数组更改为单个值

如何在 UWP 中将画布的 x、y 坐标更改为右下角?

在Mac OS X 10.6上的Python中,无法在Matplotlib中将字体更改为Helvetica

如何在python中将垂直字符串更改为水平字符串?

如何在熊猫时间序列图中将 xticks 更改为年间隔