简体   繁体   English

我是否需要使用内存屏障来保护共享资源?

[英]Do I need to use memory barriers to protect a shared resource?

In a multi-producer, multi-consumer situation. 在多生产者,多消费者的情况下。 If producers are writing into int a , and consumers are reading from int a , do I need memory barriers around int a ? 如果生产者写入int a ,并且消费者正在读取int a ,我是否需要围绕int a内存屏障?

We all learned that: Shared resources should always be protected and the standard does not guarantee a proper behavior otherwise. 我们都了解到:共享资源应该始终受到保护,标准不能保证正确的行为。

However on cache-coherent architectures visibility is ensured automatically and atomicity of 8, 16, 32 and 64 bit variables MOV operation is guaranteed. 然而,在高速缓存一致的体系结构上,可以自动确保可见性,并且保证8,16,32和64位变量的原子性MOV操作。

Therefore, why protect int a at all? 因此,为什么要保护int a

At least in C++11 (or later), you don't need to (explicitly) protect your variable with a mutex or memory barriers. 至少在C ++ 11(或更高版本)中,您不需要(明确地)使用互斥锁或内存屏障保护您的变量。

You can use std::atomic to create an atomic variable. 您可以使用std::atomic来创建原子变量。 Changes to that variable are guaranteed to propagate across threads. 对该变量的更改保证跨线程传播。

std::atomic<int> a;

// thread 1:
a = 1;

// thread 2 (later):
std::cout << a;    // shows `a` has the value 1.

Of course, there's a little more to it than that--for example, there's no guarantee that std::cout works atomically, so you probably will have to protect that (if you try to write from more than one thread, anyway). 当然,还有更多的东西 - 例如,不能保证std::cout原子地工作,所以你可能必须保护它(如果你试图从多个线程写入,无论如何)。

It's then up to the compiler/standard library to figure out the best way to handle the atomicity requirements. 然后由编译器/标准库来确定处理原子性要求的最佳方法。 On a typical architecture that ensures cache coherence, it may mean nothing more than "don't allocate this variable in a register". 在确保高速缓存一致性的典型体系结构中,它可能仅仅意味着“不要在寄存器中分配此变量”。 It could impose memory barriers, but is only likely to do so on a system that really requires them. 它可能会造成内存障碍,但只能在真正需要它们的系统上实现。

However on cache-coherent architectures visibility is ensured automatically and atomicity of 8, 16, 32 and 64 bit variables MOV operation is guaranteed. 然而,在高速缓存一致的体系结构上,可以自动确保可见性,并且保证8,16,32和64位变量的原子性MOV操作。

Unless you strictly adhere to the requirements of the C++ spec to avoid data races, the compiler is not obligated to make your code function the way it appears to. 除非您严格遵守C ++规范的要求以避免数据争用,否则编译器没有义务按照它的方式使您的代码功能化。 For example: 例如:

int a = 0, b = 0; // shared variables, initialized to zero

a = 1;
b = 1;

Say you do this on your fully cache-coherent architecture. 假设您在完全缓存一致的架构上执行此操作。 On such hardware it would seem that since a is written before b no thread will ever be able to see b with a value of 1 without a also having that value. 在这样的硬件上,似乎因为a是在b之前编写的,所以没有线程将能够看到值为1的b而没有具有该值。

But this is not the case. 但这种情况并非如此。 If you have failed to strictly adhere to the requirements of the C++ memory model for avoiding data races, eg you read these variables without the correct synchronization primitives being inserted anywhere, then your program may in fact observe b being written before a. 如果您未能严格遵守C ++内存模型的要求以避免数据争用,例如,如果没有在任何地方插入正确的同步原语而读取这些变量,那么您的程序实际上可能会在a之前观察到b被写入。 The reason is that you have introduce "undefined behavior" and the C++ implementation has no obligation to do anything that makes sense to you. 原因是您已经引入了“未定义的行为”,并且C ++实现没有义务对您做任何有意义的事情。

What may be going on in practice, is that the compiler may reorder writes even if the hardware works very hard to make it seem as if all writes occur in the order of the machine instructions performing the writes. 在实践中可能发生的是, 编译器可能会重新排序写入,即使硬件非常难以使其看起来好像所有写入都按照执行写入的机器指令的顺序发生。 You need the entire toolchain to cooperate, and cooperation from just the hardware, such as strong cache coherency, is not sufficient. 您需要整个工具链才能进行合作,而仅仅通过硬件进行协作(例如强大的缓存一致性)是不够的。


The book C++ Concurrency in Action is a good source if you care to learn about the details of the C++ memory model and writing portable, concurrent code in C++. 如果您想了解C ++内存模型的细节并在C ++中编写可移植的并发代码,那么C ++ Concurrency in Action是一个很好的资源。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 我是否需要在共享内存对象上使用shm_unlink? - Do I need to use shm_unlink on a shared memory object? 记忆障碍,不确定我是否可以放松使用? - Memory barriers, unsure if I can use relaxed? 我们需要多少个内存屏障来实现彼得森锁? - How many memory barriers do we need to implement a Peterson lock? std :: shared_ptr的use_count()周围的全部内存屏障是否会使它成为可靠的计数器? - Will full memory barriers around std::shared_ptr's use_count() make it a reliable counter? 我怎么知道使用boost在c ++中锁定需要保护的共享变量? - How do I know what shared variables I need to protect with a lock in c++ using boost? 为什么libc ++的shared_ptr实现使用全内存屏障而不是放松? - Why does libc++'s implementation of shared_ptr use full memory barriers instead of relaxed? 如何保护两个进程之间共享 memory 中的字符串? - How do I protect a character string in shared memory between two processes? 在这种特殊情况下,我是否需要共享内存中的原子类型? - Do I need an atomic type in shared memory in this particular case? 我们是否需要在Intel x86上使用C ++原子的内存屏障? - Do we ever need memory barriers with C++ atomics on Intel x86? 为什么内存屏障取决于变量? - Why do memory barriers depend upon a variable?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM