C语言中内存分布及程序运行中(BSS段、数据段、代码段、堆栈) - 秦宝艳的个人页面 - 开源中国 https://my.oschina.net/pollybl1255/blog/140323

Memory model - cppreference.com https://en.cppreference.com/w/c/language/memory_model

内存模型 - cppreference.com https://zh.cppreference.com/w/c/language/memory_model

Memory model - cppreference.com https://en.cppreference.com/w/cpp/language/memory_model

内存模型

 
 
 
 

为 C 抽象机的目的,定义计算机内存存储的语义。

可用于 C 程序的数据存储(内存)是一个或多个连续字节的序列。内存中每个字节拥有唯一的地址

字节

字节是内存的最小可寻址单元。它定义为一系列连续的位,足以保有任何基础执行字符集(要求 96 个字符是单字节)。 C 支持大小为 8 位或更多的字节。

char 、 unsigned char 及 signed char 类型的存储和值表示都使用一个字节。字节的位数可以用 CHAR_BIT 访问。

对于用字节表示其他基础类型的(包含大端与小端内存布局),见对象表示

内存位置

内存位置

  • 一个标量类型(算术类型、指针类型、枚举类型)的对象
  • 或非零长位域的最大连续序列
struct S {
char a; // 内存位置 #1
int b : 5; // 内存位置 #2
int c : 11, // 内存位置 #2 (连续)
: 0,
d : 8; // 内存位置 #3
struct {
int ee : 8; // 内存位置 #4
} e;
} obj; // 对象“ obj ”由 4 个分离的内存位置组成

线程及数据竞争

执行的线程是一个程序中的控制流,它以调用顶层函数 thrd_create 或其他方法起始。

任意线程可潜在地访问程序中的任意对象(拥有自动及线程局域存储期的对象仍能通过指针被另一线程访问)。

执行的不同线程始终允许同时访问(读或修改)不同的内存位置,这没有冲突和同步要求(注意同时更新二个同一结构体内的非原子位域是不安全的,若所有声明于其间的成员亦为(非零长)位域,不管那些插入的位域大小是多少)。

一个表达式的求值写入一个内存位置,而另一求值读取或修改同一内存位置时,我们称这两个表达式冲突。拥有两个冲突表达式的程序有数据竞争,除非

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

(特别是, mtx_unlock 与另一线程的 mtx_lock 同步,从而先发生于后者,这使得可以用互斥锁保证排除数据竞争)

  本节未完成
原因:一或二个小示例

内存顺序

线程从一个内存位置读取值时,它可能看到初始值、被同一线程写入的值,或被其他线程写入的值。关于线程所做的写入对其他线程变得可见的顺序细节,见 memory_order 。

(C11 起)

引用

  • C11 standard (ISO/IEC 9899:2011):
  • 3.6 byte (p: 4)
  • 3.14 memory location (p: 5)
  • 5.1.2.4 Multi-threaded executions and data races (p: 17-21)
  • C99 standard (ISO/IEC 9899:1999):
  • 3.6 byte (p: 4)
  • C89/C90 standard (ISO/IEC 9899:1990):
  • 1.6 DEFINITIONS OF TERMS

参阅

内存模型 的 C++ 文档

Memory model

Defines the semantics of computer memory storage for the purpose of the C abstract machine.

The data storage (memory) available to a C program is one or more contiguous sequences of bytes. Each byte in memory has a unique address.

Byte

byte is the smallest addressable unit of memory. It is defined as a contiguous sequence of bits, large enough to hold any member of the basic execution character set (the 96 characters that are required to be single-byte). C supports bytes of sizes 8 bits and greater.

The types char, unsigned char, and signed char use one byte for both storage and value representation. The number of bits in a byte is accessible as CHAR_BIT.

For use of bytes to representation values of other fundamental types (including big-endian and little-endian memory layouts), see object representation

Memory location

memory location is

  • an object of scalar type (arithmetic type, pointer type, enumeration type)
  • or the largest contiguous sequence of bit fields of non-zero length
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

Threads and data races

A thread of execution is a flow of control within a program that begins with the invocation of a top-level function by thrd_create or other means.

Any thread can potentially access any object in the program (objects with automatic and thread-local storage duration may still be accessed by another thread through a pointer).

Different threads of execution are always allowed to access (read and modify) different memory locationsconcurrently, with no interference and no synchronization requirements. (note that it is not safe to concurrently update two non-atomic bit-fields in the same structure if all members declared between them are also (non-zero-length) bit-fields, no matter what the sizes of those intervening bit-fields happen to be)

When an evaluation of an expression writes to a memory location and another evaluation reads or modifies the same memory location, the expressions are said to conflict. A program that has two conflicting evaluations has a data race unless either

If a data race occurs, the behavior of the program is undefined.

(in particular, mtx_unlock is synchronized-with, and therefore, happens-before mtx_lock of the same mutex by another thread, which makes it possible to use mutex locks to guard against data races)

  This section is incomplete
Reason: small example or two

Memory order

When a thread reads a value from a memory location, it may see the initial value, the value written in the same thread, or the value written in another thread. See memory_order for details on the order in which writes made from threads become visible to other threads.

(since C11)

References

  • C11 standard (ISO/IEC 9899:2011):
  • 3.6 byte (p: 4)
  • 3.14 memory location (p: 5)
  • 5.1.2.4 Multi-threaded executions and data races (p: 17-21)
  • C99 standard (ISO/IEC 9899:1999):
  • 3.6 byte (p: 4)
  • C89/C90 standard (ISO/IEC 9899:1990):
  • 1.6 DEFINITIONS OF TERMS

See also

C++ documentation for Memory model

Memory model

Defines the semantics of computer memory storage for the purpose of the C++ abstract machine.

The memory available to a C++ program is one or more contiguous sequences of bytes. Each byte in memory has a unique address.

Byte

byte is the smallest addressable unit of memory. It is defined as a contiguous sequence of bits, large enough to hold the value of any UTF-8 code unit (256 distinct values) and of (since C++14)any member of the basic execution character set (the 96 characters that are required to be single-byte). Similar to C, C++ supports bytes of sizes 8 bits and greater.

The types char, unsigned char, and signed char use one byte for both storage and value representation. The number of bits in a byte is accessible as CHAR_BIT or std::numeric_limits<unsigned char>::digits.

Memory location

memory location is

  • an object of scalar type (arithmetic type, pointer type, enumeration type, or std::nullptr_t)
  • or the largest contiguous sequence of bit fields of non-zero length

Note: Various features of the language, such as references and virtual functions, might involve additional memory locations that are not accessible to programs but are managed by the implementation.

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

Threads and data races

A thread of execution is a flow of control within a program that begins with the invocation of a top-level function by std::thread::threadstd::async, or other means.

Any thread can potentially access any object in the program (objects with automatic and thread-local storage durationmay still be accessed by another thread through a pointer or by reference).

Different threads of execution are always allowed to access (read and modify) different memory locationsconcurrently, with no interference and no synchronization requirements.

When an evaluation of an expression writes to a memory location and another evaluation reads or modifies the same memory location, the expressions are said to conflict. A program that has two conflicting evaluations has a data raceunless

  • both evaluations execute on the same thread or in the same signal handler, or
  • both conflicting evaluations are atomic operations (see std::atomic), or
  • one of the conflicting evaluations happens-before another (see std::memory_order)

If a data race occurs, the behavior of the program is undefined.

(In particular, release of a std::mutex is synchronized-with, and therefore, happens-before acquisition of the same mutex by another thread, which makes it possible to use mutex locks to guard against data races.)

int cnt = 0;
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

Memory order

When a thread reads a value from a memory location, it may see the initial value, the value written in the same thread, or the value written in another thread. See std::memory_order for details on the order in which writes made from threads become visible to other threads.

Forward progress

Obstruction freedom

When only one thread that is not blocked in a standard library function executes an atomic function that is lock-free, that execution is guaranteed to complete (all standard library lock-free operations are obstruction-free)

Lock freedom

When one or more lock-free atomic functions run concurrently, at least one of them is guaranteed to complete (all standard library lock-free operations are lock-free -- it is the job of the implementation to ensure they cannot be live-locked indefinitely by other threads, such as by continuously stealing the cache line)

Progress guarantee

In a valid C++ program, every thread eventually does one of the following:

  • terminate
  • makes a call to an I/O library function
  • performs an access through a volatile glvalue
  • performs an atomic operation or a synchronization operation

No thread of execution can execute forever without performing any of these observable behaviors.

Note that it means that a program with endless recursion or endless loop (whether implemented as a for-statement or by looping goto or otherwise) has undefined behavior. This allows the compilers to remove all loops that have no observable behavior, without having to prove that they would eventually terminate.

A thread is said to make progress if it performs one of the execution steps above (I/O, volatile, atomic, or synchronization), blocks in a standard library function, or calls an atomic lock-free function that does not complete because of a non-blocked concurrent thread.

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++ 抽象机的目的定义了计算机内存存储的语义。

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

字节

字节(byte)是最小的可寻址内存单元。它被定义为相接的位序列,其大到足以保有任何 UTF-8 编码单元(256 个相异值)和(C++14 起)基本执行字符集96 个字符,要求必为单字节)的任何成员。与 C 相似,C++ 也支持 8 位或更大的字节。

char、unsigned char 和 signed char 类型把一个字节用于存储和值表示。字节中的位数可作为 CHAR_BIT 或 std::numeric_limits<unsigned char>::digits 访问。

内存位置

内存位置

  • 一个标量类型(算术类型、指针类型、枚举类型或 std::nullptr_t)对象
  • 或非零长位域的最大相接序列

注意:语言的各种功能特性,例如引用虚函数,可能涉及到程序不可访问,但为实现所管理的额外内存位置。

struct S {
char a; // 内存位置 #1
int b : 5; // 内存位置 #2
int c : 11, // 内存位置 #2 (延续)
: 0,
d : 8; // 内存位置 #3
struct {
int ee : 8; // 内存位置 #4
} e;
} obj; // 对象 'obj' 由 4 个分离的内存位置组成

线程与数据竞争

执行线程是程序中的控制流,它始于 std::thread::threadstd::async 或以其他方式所进行的顶层函数调用。

任何线程都能潜在地访问程序中的任何对象(拥有自动或线程局部存储期的对象仍可为另一线程通过指针或引用访问)。

始终允许不同的执行线程同时访问(读和写)不同的内存位置,而无干涉或同步的任何要求。

当某个表达式的求值写入某个内存位置,而另一求值读或修改同一内存位置时,称这些表达式冲突。拥有两个冲突的求值的程序就有数据竞争,除非

  • 两个求值都在同一线程上,或同一信号处理函数中执行,或
  • 两个冲突的求值都是原子操作(见 std::atomic ),或
  • 一个冲突的求值发生早于(happens-before)另一个(见 std::memory_order

若出现数据竞争,则程序的行为未定义。

(特别是,std::mutex 的释放同步于,从而发生早于另一线程对同一 mutex 的获取,这使得可以用互斥锁来防止数据竞争)

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

内存顺序

当线程从某个内存位置读取值时,它可能看到初值,同一线程所写入的值,或另一线程所写入的值。有关线程所作的写入操作对其他线程变为可见的顺序上的细节,见 std::memory_order

向前进展

免妨碍

当只有一个未在标准库函数中阻塞的线程执行某个免锁的原子函数时,保证该执行将会完成(所有标准库免锁操作均为免妨碍的)。

免锁

当一或多个免锁原子函数同时运行时,保证其中至少一个将会完成(所有标准库免锁操作均为免锁的——确保其他线程不能不确定地活锁它们(例如以连续窃取缓存线的方式),是实现的工作)。

进展保证

合法的 C++ 程序中,每个线程最终要做下列之一:

  • 终止
  • 调用 I/O 库函数
  • 通过 volatile 泛左值进行访问
  • 进行原子操作或同步操作

没有线程能永远执行,而不做任何这些可观察行为。

注意,这意味着包含无限递归或无限循环(无论是实现为 for 语句 或是用 goto 循环还是其他方式)的程序具有未定义行为。这允许编译器移除所有无可观察行为的循环,而不必证明他们终将终止。

若线程执行了上述步骤之一(I/O、volatile、原子或同步操作),阻塞于标准库函数中,或调用由于某个未阻塞的并发线程而未能完成的原子免锁函数,则称它取得进展(make progress)

并发向前进展

若线程提供并发向前进展保证(concurrent forward progress guarantee),则只要它尚未终止,就将在有限量的时间内取得进展(定义如上),无关乎其他线程(若存在)是否取得进展。

标准鼓励但不要求主线程和 std::thread 所启动的线程提供并发向前进展保证。

并行向前进展

若线程提供并行向前进展保证(parallel forward progress guarantee),则若线程尚未执行任何执行步骤(I/O、volatile、原子或同步操作),就不要求实现保证该线程终将取得进展,但一旦此线程开始执行步骤,则它提供并发向前进展保证(此规则描述线程池中以任意顺序执行任务的线程)。

弱并行向前进展

若线程提供弱并行向前进展保证(weakly parallel forward progress guarantee),则不保证它终将取得进展,无关乎其他线程是否取得进展。

仍然能通过以向前进展保证委托进行阻塞来保证这种线程取得进展:若线程 P 以此方式阻塞于线程集合 S 的完成,则 S 中至少有一个线程将提供等于或强于 P 的向前进展保证。一旦该线程完成,则类似地强化 S 中的另一线程。一旦集合为空,则将解除 P 的阻塞。

来自 C++ 标准库的并行算法,均以向前保证委托阻塞于某个标准库所管理的线程的未指明集合的完成上。

(C++17 起)

参阅

内存模型 的 C 文档

内存模型

 
 
 
 

为 C 抽象机的目的,定义计算机内存存储的语义。

可用于 C 程序的数据存储(内存)是一个或多个连续字节的序列。内存中每个字节拥有唯一的地址

字节

字节是内存的最小可寻址单元。它定义为一系列连续的位,足以保有任何基础执行字符集(要求 96 个字符是单字节)。 C 支持大小为 8 位或更多的字节。

char 、 unsigned char 及 signed char 类型的存储和值表示都使用一个字节。字节的位数可以用 CHAR_BIT 访问。

对于用字节表示其他基础类型的(包含大端与小端内存布局),见对象表示

内存位置

内存位置

  • 一个标量类型(算术类型、指针类型、枚举类型)的对象
  • 或非零长位域的最大连续序列
struct S {
char a; // 内存位置 #1
int b : 5; // 内存位置 #2
int c : 11, // 内存位置 #2 (连续)
: 0,
d : 8; // 内存位置 #3
struct {
int ee : 8; // 内存位置 #4
} e;
} obj; // 对象“ obj ”由 4 个分离的内存位置组成

线程及数据竞争

执行的线程是一个程序中的控制流,它以调用顶层函数 thrd_create 或其他方法起始。

任意线程可潜在地访问程序中的任意对象(拥有自动及线程局域存储期的对象仍能通过指针被另一线程访问)。

执行的不同线程始终允许同时访问(读或修改)不同的内存位置,这没有冲突和同步要求(注意同时更新二个同一结构体内的非原子位域是不安全的,若所有声明于其间的成员亦为(非零长)位域,不管那些插入的位域大小是多少)。

一个表达式的求值写入一个内存位置,而另一求值读取或修改同一内存位置时,我们称这两个表达式冲突。拥有两个冲突表达式的程序有数据竞争,除非

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

(特别是, mtx_unlock 与另一线程的 mtx_lock 同步,从而先发生于后者,这使得可以用互斥锁保证排除数据竞争)

  本节未完成
原因:一或二个小示例

内存顺序

线程从一个内存位置读取值时,它可能看到初始值、被同一线程写入的值,或被其他线程写入的值。关于线程所做的写入对其他线程变得可见的顺序细节,见 memory_order 。

(C11 起)

引用

  • C11 standard (ISO/IEC 9899:2011):
  • 3.6 byte (p: 4)
  • 3.14 memory location (p: 5)
  • 5.1.2.4 Multi-threaded executions and data races (p: 17-21)
  • C99 standard (ISO/IEC 9899:1999):
  • 3.6 byte (p: 4)
  • C89/C90 standard (ISO/IEC 9899:1990):
  • 1.6 DEFINITIONS OF TERMS

参阅

内存模型 的 C++ 文档

内存模型 Memory model 内存分布及程序运行中(BSS段、数据段、代码段、堆栈的更多相关文章

  1. C语言中内存分布及程序运行中(BSS段、数据段、代码段、堆栈)

      BSS段:(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域.BSS是英文Block Started by Symbol的简称.BSS段属于静态内存分配. 数据段 : ...

  2. 程序运行中(BSS段、数据段、代码段、堆栈)

    程序运行中(BSS段.数据段.代码段.堆栈) BSS段:(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域.BSS是英文Block Started by Symbol的简 ...

  3. c++11 standardized memory model 内存模型

    C++11 标准中引入了内存模型,其目的是为了解决多线程中可见性和顺序(order).这是c++11最重要的新特征,标准忽略了平台的差异,从语义层面规定了6种内存模型来实现跨平台代码的兼容性.多线程代 ...

  4. 硬件内存模型到 Java 内存模型,这些硬核知识你知多少?

    Java 内存模型跟上一篇 JVM 内存结构很像,我经常会把他们搞混,但其实它们不是一回事,而且相差还很大的,希望你没它们搞混,特别是在面试的时候,搞混了的话就会答非所问,影响你的面试成绩,当然也许你 ...

  5. Java 内存模型和硬件内存架构笔记

    前言 可跟<主存存取和磁盘存取原理笔记>串着看 https://blog.csdn.net/suifeng3051/article/details/52611310 杂技 Java 内存模 ...

  6. 内存泄漏 Memory Leaks 内存优化 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  7. Redis内存模型(1):内存统计及划分

    1. 内存统计 查看命令:info memory 示例: 部分含义: used_memory: Redis分配器分配的内存总量(单位是字节),包括使用的虚拟内存. used_memory_rss: R ...

  8. Linux 系统运行着许多子系统和应用程序。您可以使用系统日志记录从启动时就收集有关运行中系统的数据。有时

    概述 在本教程中,您将学习以下内容: 配置 syslog 守护程序 了解标准设施.优先级和操作 配置日志轮换 了解 rsyslog 和 syslog-ng 系统内部发生了什么 Linux 系统运行着许 ...

  9. Java内存模型、JVM内存结构和Java对象模型

    JVM内存结构 我们都知道,Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途.其中有些区域随着虚拟机进程的启动而存 ...

随机推荐

  1. Nginx 配置日志路径(nginx.conf没有写log路径,所以debug的时候找不到日志)

    缘由:nginx.conf没有写log路径,所以debug的时候找不到日志,遂在conf文件里写入了log路径 Setp1.nginx默认日志路径: /var/log/nginx Setp2.conf ...

  2. JVM 经典垃圾收集器 —— CMS 收集器

    本文部分摘自<深入理解 Java 虚拟机第三版> 概述 CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器.由于大部分 Java 应用主要 ...

  3. 初识Web Service

    Web Service 今天新接了一个小项目,要用webservice.把示例代码拿过来一看,我有点懵.这啥东西?虽然调试了一下,找猫画虎也算调成功了,但是对这个webservice还是不太了解. 下 ...

  4. easyui获取table列表中所有数据组装成json格式发送到后台

    jsp代码 var rows =$('#findAllRolestable').datagrid('getSelections'); var result = JSON.stringify(rows) ...

  5. #3使用html+css+js制作网页 番外篇 制作接收php

    使用html+css+js制作网页 番外篇 制作接收php 本系列链接 基础 php语法 例子 本系列链接 #1使用html+css+js制作网站教程 准备 #2使用html+css+js制作网站教程 ...

  6. Docker一秒进阶

    tar包: 从tar包导入:docker load < xxxx.tar docker run -d -p 8080:80 --name [名字] -v `pwd`:/usr/share/ngi ...

  7. Petalinux和Vivado的安装

    Petalinux和Vivado的安装 背景 我是搞软件的, FPGA这块不太了解.由于机缘巧合,最近有接触到这块的开发.所以先挖一坑. 先声明我不是专业搞这块的,所以对这块的内容理解可能会有偏差,以 ...

  8. Laya 踩坑日记-人物模型穿模,模型显示不正常

    最近做游戏,人物要跑到很远的位置,z轴距离大概有20000个单位,然后就发现一个bug,到远处人物模型穿了,而且没办法改,这就尴尬了 Z轴对应值    0    100000 100000 当距离零点 ...

  9. ruby+watir安装指南

    安装ruby+watir一共需要下面几个步骤 1. 安装ruby: 2. 升级Rubygems:Rubygems(简称 gems)是一个用于对 Ruby组件进行打包的 Ruby 打包系统. 它提供一个 ...

  10. maven依赖与传递性依赖

    目录 依赖范围 传递性依赖 依赖调节 可选依赖 本文主要是针对<maven实战>书中关键知识点的学习记录,未免有纰漏或描述不到之处,建议购买阅读原书 首先贴出一个pom常见的一些元素释义 ...