相邻内存区域上的 memcpy() 安全性

Posted

技术标签:

【中文标题】相邻内存区域上的 memcpy() 安全性【英文标题】:memcpy() safety on adjacent memory regions 【发布时间】:2011-01-14 19:45:30 【问题描述】:

我最近在using volatile 上提出了一个问题,并被指示阅读英特尔和其他人关于内存屏障及其用途的一些非常 信息丰富的文章。读完这些文章后,我变得很偏执。

我有一台 64 位机器。从多个线程 memcpy 到相邻的、非重叠的内存区域是否安全?例如,假设我有一个缓冲区:

char buff[10];

一个线程将内存存储到前 5 个字节,而第二个线程复制到最后 5 个字节是否总是安全?

我的直觉反应(和一些简单的测试)表明这是完全安全的,但我无法在任何地方找到可以完全说服我的文档。

【问题讨论】:

【参考方案1】:

安全,是的。至少在这个有限的例子中是高性能的,不。请记住,一个高速缓存行不能同时位于两个内核中。您将强制核心 A 在核心 B 写入缓冲区时等待,然后在内存传输时等待,然后再写入。多核内存副本的大小应该非常大以避免这种影响。

【讨论】:

这取决于处理器、内存是否被声明为易失性以及编译器的优化级别。通常,每个核心将写入自己的缓存副本,处理器将在随后的刷新期间解决该副本。这确实表明,真正的内存同步屏障对于从实际尝试读取已写入的内存中获得确定性行为是完全必要的。 x86/x64 和许多其他处理器是缓存一致的 (en.wikipedia.org/wiki/Cache_coherency)。两个核心可以拥有相同的缓存行,并且两个副本将始终保持最新,以便它们拥有相同的值。当然,如前所述,从两个内核访问同一缓存行会对性能产生巨大影响。 @Adam:幸运的是我只担心写作——任何读取都将发生在很远的将来。否则,我可能会更加偏执。 我正在观看有关 Microsoft 最新并发库的视频,他们说缓存行共享是他们在使看似不错的代码实际工作时遇到的最大问题。修复后,它将在 24 个内核上将代码从 40% 缩放更改为 100% 缩放。虚假共享不是小问题,它会带来严重的问题。 Adam 仍然是正确的,它取决于处理器。提问者只说“我有一台 64 位机器”。我 99.9% 确定这意味着 x64,但并非所有 64 位处理器都是 x64/IA64。有关于 64 位 ARM 的讨论,而 ARM 架构并不总是有一致的缓存,在这种情况下,那些相邻的写入可能是非线程安全的。那么虚假共享就变成了一个正确性问题,而不仅仅是一个性能问题。【参考方案2】:

是的,它完全安全,对内存总线的序列化访问是在硬件中完成的。

【讨论】:

【参考方案3】:

只要 memcpy 的每个实例都认为它只写入缓冲区的一部分,它就是完全安全的。 C++ 中任何形式的数组分配都是非常底层的;它是以适当大小为程序分配的连续存储块,而数组作为对象存在,除了指针之外的任何东西都只是一种错觉。给 memcpy 数组的非重叠范围,它无法知道它们不仅仅是两个恰好彼此相邻的完全独立的数组。写入不会干扰。

【讨论】:

MemCpy?更像 memcpy。更重要的是OP关心从不同线程同时访问内存的问题。 您委婉而礼貌的文案编辑以合作精神受到赞赏。无论如何,OP 担心在不同线程中同时访问不重叠的相邻内存区域的问题,这就是我的回答。【参考方案4】:

是的,这与任何类型的先发生在订购之前完全无关。它只是复制字节。

【讨论】:

以上是关于相邻内存区域上的 memcpy() 安全性的主要内容,如果未能解决你的问题,请参考以下文章

MFC-memcpy内存区域复制

memcpy不能复制内存重叠区域

c++中内存拷贝函数(C++ memcpy)详解

memcpy和strcpy的区别

memcpy和strcpy的区别

memcpy的用法总结