MOVNTI 存储是否相对于由同一线程创建的其他 MOVNTI 存储重新排序?
Are MOVNTI stores reordered relative to other MOVNTI stores made by the same thread?
TL;博士: 我知道 MOVNTI 操作相对于程序的其余部分没有顺序,因此需要 SFENCE/MFENCE。 但是,MOVNTI 操作相对于同一线程的其他 MOVNTI 操作不是按顺序排列的吗?
假设我有一个生产者-消费者队列,并且我想在生产者端使用 MOVNTI 以避免缓存污染。
(还没有真正观察到缓存污染效应,所以现在可能是理论问题(
所以我要替换以下生产者:
std::atomic<std::size_t> producer_index;
QueueElement queue_data[MAX_SIZE];
...
void producer()
{
for (;;)
{
...
queue_data[i].d1 = v1;
queue_data[i].d2 = v2;
...
queue_data[i].dN = vN;
producer_index.store(i, std::memory_order_release);
}
}
具有以下功能:
void producer()
{
for (;;)
{
...
_mm_stream_si64(&queue_data[i].d1, v1);
_mm_stream_si64(&queue_data[i].d2, v2);
...
_mm_stream_si64(&queue_data[i].dN, vN);
_mm_sfence();
producer_index.store(i, std::memory_order_release);
}
}
请注意,我添加了_mm_sfence
,它将等到"非时间"操作结果变得可观察。 如果我不添加它,consumer
可能会在queue_data
更改之前观察producer_index
。
但是,如果我也用_mm_stream_si64
编写索引呢?
std::size_t producer_index_value;
std::atomic_ref<std::size_t> producer_index { producer_index_value };
void producer()
{
for (;;)
{
...
_mm_stream_si64(&queue_data[i].d1, v1);
_mm_stream_si64(&queue_data[i].d2, v2);
...
_mm_stream_si64(&queue_data[i].dN, vN);
_mm_stream_si64(&producer_index_value, i);
}
}
根据我对英特尔手册的阅读,这应该行不通,因为非临时商店已经放松了订购。
但是,他们不是说"放松"只是为了使非时间操作不针对程序的其余部分下令吗? 也许它们是在自己内部排序的,所以producer
仍然会按预期工作?
如果 MOVNTI 真的放宽了,以至于最新的代码不正确,那么内存写入重新排序的原因是什么?
movnti
存储相对于彼此的排序也很弱。 在asm中,您肯定需要在存储数据后sfence
以获取存储producer_index
的发布语义,无论您是使用movnti
还是普通mov
存储
。大多数情况下,在使用 NT 存储进行一些全行写入之前,单独的存储不会对其他线程可见。 实际上可能:完成缓存行会触发WC缓冲区到DRAM的刷新(绕过/逐出缓存(,但索引绝对不会是全行存储,除非它恰好与写入数据的末尾相邻。
在C++,这意味着在您执行存储到producer_index
之前使用_mm_sfence()
。
请注意,对单个标量使用movnti
是一个非常糟糕的主意:它强制从缓存中逐出缓存行,因此读取器必须从 DRAM 中一直获取它。 也就是说,它将增加该控制变量的核心间延迟,否则可能会在 L3 中命中。
仅当您希望完成整个缓存行时,并且不希望另一个线程很快重新加载数据时,才使用 NT 存储。
- 将字符串存储在c++中的稳定内存中
- std::原子加载和存储都需要吗
- C++:将控制台输出存储在宏中更好吗
- 使用QProcess执行命令,并将结果存储在QStringList中
- 访问存储在向量C++中的结构的多态成员
- 如何从存储在std::映射中的std::集中删除元素
- 存储模板类型以强制转换回派生<T>
- 类型总是使用其大小存储在内存中吗
- 当字符串存储在变量中时,如何将字符串转换为wchar_t
- 使用无符号字符数组有效存储内存
- 如何在cpp.中使用协议缓冲区存储大缓冲区/数组(char/int)
- 使用 pqxx 将 std::vector 存储在 postgresql 中,并从数据库中检索它
- 带结构的二维矢量:如何存储元素
- 添加存储在向量中的大整数的函数出现问题
- 从文件中读取多个字节,并将它们存储在C++中进行比较
- 在std::vector上存储带有模板的类实例
- 谷歌测试中的期望值存储在哪里
- 为什么C中的通用链表中存储的数据已损坏
- 在c++中获取两个大int,并将它们存储在数组中
- MOVNTI 存储是否相对于由同一线程创建的其他 MOVNTI 存储重新排序?