Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 并发性:C+中的原子性和易失性+;11存储器模型_C++_Multithreading_Concurrency_C++11_Parallel Processing - Fatal编程技术网

C++ 并发性:C+中的原子性和易失性+;11存储器模型

C++ 并发性:C+中的原子性和易失性+;11存储器模型,c++,multithreading,concurrency,c++11,parallel-processing,C++,Multithreading,Concurrency,C++11,Parallel Processing,全局变量在两个不同内核上的两个并发运行线程之间共享。线程对变量进行写入和读取。对于原子变量,一个线程能否读取过时的值?每个核心的缓存中可能都有一个共享变量的值,当一个线程在缓存中写入其副本时,不同核心上的另一个线程可能会从自己的缓存中读取过时的值。或者编译器执行强内存排序以从另一个缓存读取最新值?c++11标准库具有std::atomic支持。这与volatile关键字有何不同?在上述场景中,volatile和atomic类型的行为如何不同?volatile和atomic操作具有不同的背景,以及

全局变量在两个不同内核上的两个并发运行线程之间共享。线程对变量进行写入和读取。对于原子变量,一个线程能否读取过时的值?每个核心的缓存中可能都有一个共享变量的值,当一个线程在缓存中写入其副本时,不同核心上的另一个线程可能会从自己的缓存中读取过时的值。或者编译器执行强内存排序以从另一个缓存读取最新值?c++11标准库具有std::atomic支持。这与volatile关键字有何不同?在上述场景中,volatile和atomic类型的行为如何不同?

volatile
和atomic操作具有不同的背景,以及 是以不同的目的介绍的

volatile
可追溯到很久以前,主要用于防止 访问内存映射IO时的编译器优化。现代的 编译器只会抑制对
volatile
的优化, 尽管在某些机器上,这对于内存映射来说是不够的 木卫一。除了信号处理程序的特殊情况和
setjmp
longjmp
getjmp
序列(其中C标准 对于信号,Posix标准提供了额外的保证),必须 在现代机器上被认为是无用的,没有特殊的附加功能 指令(围栏或内存屏障),硬件可以重新排序或 甚至禁止某些访问。因为您不应该使用
setjmp
在C++中,或多或少地留下信号处理程序,并且在一个 多线程环境,至少在Unix下,有更好的 这些问题的解决方案也是如此。可能还有内存映射IO,如果您 处理内核代码,可以确保编译器生成 所讨论的平台需要什么。(根据 标准的,
volatile
访问是可观察的行为,由编译器执行 必须尊重。但是编译器可以定义 “访问”,大多数人似乎将其定义为“负载或负载” 存储机器指令被执行“,在现代 处理器,甚至不意味着一定要读或写 在公共汽车上骑车,更不用说按你期望的顺序了。)

给出这种情况,C++标准增加了原子访问,这是 跨线程提供一定数量的保证;特别地, 围绕原子访问生成的代码将包含必要的 防止硬件重新排序的附加说明 访问,并确保访问向下传播到全局 多核机器上的核之间共享的内存。(在 在标准化工作中,微软提议将这些语义添加到 <代码> Value,我想他们的C++编译器有一些。 然而,在委员会讨论这些问题时,秘书长 包括微软代表在内的共识是 最好将

volatile
保留其原始含义,并定义 原子类型)或只使用系统级原语,如 互斥体,它执行代码中所需的任何指令。 (他们必须这样做。如果没有一些保证,就无法实现互斥
关于内存访问的顺序。)

首先,
volatile
并不意味着原子访问。它设计用于内存映射I/O和信号处理等方面<当与
std::atomic
一起使用时,
volatile
是完全不必要的,除非您的平台另有说明,
volatile
与线程之间的原子访问或内存顺序无关

如果您有一个在线程之间共享的全局变量,例如:

std::atomic<int> ai;
std::原子人工智能;
然后可见性和顺序约束取决于用于操作的内存顺序参数,以及锁、线程和对其他原子变量的访问的同步效果

在没有任何额外同步的情况下,如果一个线程将一个值写入
ai
,则无法保证另一个线程在任何给定的时间段内都能看到该值。该标准规定,它应该在“一段合理的时间内”可见,但任何给定的访问都可能返回一个过时的值

std::memory_-order_-seq_-cst
的默认内存顺序为所有变量的所有
std::memory_-order_-seq_-cst
操作提供一个全局总顺序。这并不意味着您不能获得过时的值,但它确实意味着您确实获得的值决定并取决于您操作的总顺序

如果您有两个共享变量
x
y
,初始值为零,并且一个线程将1写入
x
,另一个线程将2写入
y
,那么读取这两个变量的第三个线程可能会看到(0,0)、(1,0)、(0,2)或(1,2),因为操作之间没有顺序约束,因此,操作可能以全局顺序中的任何顺序出现

如果两次写入都来自同一个线程,该线程在
y=2
之前执行
x=1
,并且读取线程在
x
之前读取
y
,则(0,2)不再是有效选项,因为读取
y==2
意味着可以看到之前对
x
的写入。其他3对(0,0)、(1,0)和(1,2)仍然是可能的,这取决于2个读操作与2个写操作的交织方式

如果使用其他内存顺序,例如
std::memory\u order\u released
std::memory\u order\u acquire
,则约束会进一步放宽,单个全局顺序不再适用。如果没有额外的同步,线程甚至不必就两个存储区的顺序达成一致,以分离变量

唯一能保证你