在 C++ 中将值从 X 更改为 X 会导致数据竞争吗? [英] Can changing a value from X to X in C++ lead to a data race?

查看:17
本文介绍了在 C++ 中将值从 X 更改为 X 会导致数据竞争吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的代码可以处理具有不同布局的大数据块.布局将决定哪些数据是固定的,哪些数据是不固定的.一旦数据被固定在一个块中,它通常不会再改变.所以所有代码读取数据总会看到相同的数据.

I have code that works with large data blocks having different layouts. The layout will determine which part of the data is fixed, and which data is not fixed. Once data is fixed in a block, it normally doesn't change anymore. So all code reading data will always see the same data.

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

However, other services may make changes in these blocks as long as they are sure that no code will read that part of the block. To simplify the code, blocks that contain a change will be sent from one service to the other, regardless of the layout of the block. The receiving service will then overwrite the complete block, including the data that was not changed. Let me illustrate this with an example:

假设我们有以下数据块:

Suppose we have the following block of data:

<头>
57239817250000000000

假设前 5 个值是固定的".我们服务中的代码只会读取前 5 个值,而永远不会读取接下来的 5 个值.由于我们的架构设计,我们可以保证这一点.接下来的 5 个值没有意义,所以我在表格中加了零来说明这一点.

And imagine that the first 5 values are 'fixed'. Code in our service will only read the first 5 values and will never read the next 5 values. We can guarantee this due to the design of our architecture. The next 5 values don't really make sense so I put zeroes in the table to illustrate this.

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

Now another service determines the next 5 values, sends the complete block to our service, and we simply overwrite the complete block with the new data. Since the first 5 values were 'fixed', they remain the same, but the code that transfers and overwrites the block, doesn't know about the layout of the block, so the only thing it can do is overwrite the complete block. This is the result:

<头>
57239817250833427185

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

As said before, the first 5 values did not change, although they were overwritten by the transfer logic.

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

Question is: Is this a data race? Is it allowed to overwrite a memory address with exactly the same value if other threads can read the data at the same time?

推荐答案

这是一场数据竞赛吗?

Is this a data race?

是的.

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

Is it allowed to overwrite a memory address with exactly the same value if other threads can read the data at the same time?

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

Not explicitly - and that's not the only issue, either.

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

If your compiler actually performs a single 8-byte load, you have a real (ie, not even potentially just theoretical) data race on the last 3 bytes. Say you have a hypothetical machine where the uint64_t value 57 23 98 17 25 00 00 42 is a trap representation, your update thread used memmove, and it copies the update backwards.

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

However, a data race means behaviour is undefined by the standard. It may be well-defined on a particular platform - such as any platform which doesn't have integer trap representations, any platform where you know the compiler will really use byte loads, or any platform with explicit semantics for idempotent stores.

参见,例如,[intro.races] 注释 23:

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

Transformations that introduce a speculative read of a potentially shared memory location might not preserve the semantics of the C++ program as defined in this document, since they potentially introduce a data race. However, they are typically valid in the context of an optimizing compiler that targets a specific machine with well-defined semantics for data races. They would be invalid for a hypothetical machine that is not tolerant of races or provides hardware race detection

(对于非投机种族没有这样的说明,对于幂等存储也没有特定的例外,但在 IMO 上采取相同的方法是合理的).

(there's no such note for non-speculative races and no specific exception for your idempotent stores, but it's reasonable to take the same approach there IMO).

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

Obviously if you can write your code so it doesn't depend on these platform details it will be more portable and less fragile in the face of compiler and/or platform updates. Just atomically swapping between two versions of a block (so you read from a copy guaranteed to be unchanging, and write to a copy guaranteed not to be shared) will always be correct, and may even be faster due to reducing cache/coherency traffic.

这篇关于在 C++ 中将值从 X 更改为 X 会导致数据竞争吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆