在线文档教程
C++
语言 | Language

Memory model

记忆模型

为C++抽象机定义了计算机内存存储的语义。

C++程序可用的内存是一个或多个连续序列字节.内存中的每个字节都有一个唯一的地址...

字节

字节是最小的可寻址内存单位。它被定义为一个连续的位序列,其大小足以容纳任意的值。UTF-8自C++14%29以来,代码单元%28256不同值%29和%28基本执行字符集%2896个字符要求为单字节%29。与C类似,C++支持大小为8位及更大的字节

大类型char,,,unsigned char,和signed char同时使用一个字节存储和值表示字节中的位数可访问为CHAR_BIT或std::numeric_limits<unsignedchar>::digits...

存储器位置

存储器位置是。

  • 对象标量型%28算术类型、指针类型、枚举类型或std::nullptr[医]t%29

  • 或最大的相邻序列位字段非零长度

注意:语言的各种特性,如参考文献和虚函数,可能涉及程序无法访问但由实现管理的其他内存位置。

二次

struct S { char a; // memory location #1 int b : 5; // memory location #2 int c : 11, // memory location #2 (continued) : 0, d : 8; // memory location #3 struct { int ee : 8; // memory location #4 } e; } obj; // The object 'obj' consists of 4 separate memory locations

二次

线程和数据竞赛

执行线程是程序中的控制流,从调用顶级函数开始。std::thread::thread,,,std::async或者其他方法。

任何线程都可以使用自动和线程本地访问程序%28对象中的任何对象。存储时间仍可由另一个线程通过指针或引用%29访问。

不同的执行线程总是允许访问%28读取和修改%29不同存储器位置同时,没有干扰和同步要求。

当评价将表达式写入内存位置,而另一个计算值读取或修改相同的内存位置,则表达式被称为冲突有两个相互冲突的评估的程序具有数据竞赛除非。

  • 两个计算都在同一个线程上或在相同的线程中执行。信号处理程序,或

  • 两个相互冲突的计算值都是原子操作%28(参见std::atomic%29,或

  • 一项相互矛盾的评价发生-之前另见28%std::memory_order%29

如果发生数据竞争,则程序的行为未定义。

%28,特别是,a的释放std::mutex同步因此,发生-之前通过另一个线程获取相同的互斥锁,这使得使用互斥锁来防止数据竞争%29成为可能。

二次

int cnt; auto f = [&]{cnt++;}; std::thread t1{f}, t2{f}, t3{f}; // undefined behavior

二次

二次

std::atomic<int> cnt{0}; auto f = [&]{cnt++;}; std::thread t1{f}, t2{f}, t3{f}; // OK

二次

记忆顺序

当线程从内存位置读取值时,它可能会看到初始值、在同一线程中写入的值或在另一个线程中写入的值。见std::memory_order有关由线程编写的写入对其他线程可见的顺序的详细信息。

向前进展

阻碍自由

当标准库函数中只有一个线程未被阻塞时,则执行原子函数这是无锁的,保证执行完成%28所有标准库无锁操作都是无障碍29%。

锁自由度

当一个或多个无锁原子函数同时运行时,至少其中一个函数保证完成%28所有标准库无锁操作无锁--实现的任务是确保它们不能被其他线程无限期地锁定,例如通过不断地窃取缓存行%29。

进度保证

在有效的C++程序中,每个线程最终执行下列操作之一:

  • 终止

  • 调用I/O库函数

  • 通过易挥发极值

  • 执行原子操作或同步操作。

任何执行线程都不可能在不执行这些可观察到的行为的情况下永远执行。

请注意,它意味着一个具有无穷递归或无休止循环%28的程序是否实现为为---声明或者通过循环后藤或者其他情况下%29已经未定义行为这允许编译器删除所有没有可观察行为的循环,而不必证明它们最终会终止。

一根线据说是取得进展如果它执行%28 I/O以上的执行步骤之一,易失性、原子性或同步%29,则在标准库函数中阻塞,或调用由于未阻塞的并发线程而未完成的原子无锁函数。

Concurrent forward progress If a thread offers concurrent forward progress guarantee, it will make progress (as defined above) in finite amount of time, for as long as it has not terminated, regardless of whether other threads (if any) are making progress. The standard encourages, but doesn't require that the main thread and the threads started by std::thread offer concurrent forward progress guarantee. Parallel forward progress If a thread offers parallel forward progress guarantee, the implementation is not required to ensure that the thread will eventually make progress if it has not yet executed any execution step (I/O, volatile, atomic, or synchronization), but once this thread has executed a step, it provides concurrent forward progress guarantees (this rule describes a thread in a thread pool that executes tasks in arbitrary order). Weakly parallel forward progress If a thread offers weakly parallel forward progress guarantee, it does not guarantee to eventually make progress, regardless of whether other threads make progress or not. Such threads can still be guaranteed to make progress by blocking with forward progress guarantee delegation: if a thread P blocks in this manner on the completion of a set of threads S, then at least one thread in S will offer a forward progress guarantee that is same or stronger than P. Once that thread completes, another thread in S will be similarly strengthened. Once the set is empty, P will unblock. The parallel algorithms from the C++ standard library block with forward progress delegation on the completion of an unspecified set of library-managed threads.(since C++17)

另见

内存模型的C文档

*。

© cppreference.com

在CreativeCommonsAttribution下授权-ShareAlike未移植许可v3.0。

http://en.cppreference.com/w/cpp/language/Memory[医]模型