C语言

第一章

预处理阶段->得到.i文件->编译阶段->得到.s文件->汇编阶段->得到.o文件(二进制文件)->链接阶段
优点:优化程序性能、理解链接时出现的错误、避免安全漏洞。
系统硬件的组成:1.总线、2.I/O设备、3.主存、4.处理器
CPU指令:加载、存储、操作、跳转
进程的虚拟空间组成:程序代码和数据、堆、共享库、栈、内核虚拟内存。

第二章 信息的表示和处理

2.1 信息存储

2.1.1 十六进制表示法

image.png

2.1.2 字数据大小

image.png

2.1.3 寻址和字节顺序

小端法:最低有效字节在最前面。
大端法:最高有效字节在最前面。
个人理解:大端,正常方向;小端,反向。


image.png

2.1.4 表示字符串

C语言中,字符串被编码为一个以NULL(其值为0)字符结尾的字符数组。每个字符都由某个标准编码来表示,最常见的是ASCII字符码。

2.1.5 表示代码

2.1.6 布尔代数简介

& - 当两边值都为1时结果才为1,其余情况都是0
| - 当两边值有一个是1,结果就为1。
^ - 两边值不同为1,相同为0。
~ - 两边取反


image.png

image.png

2.1.7 C语言中的位级运算

image.png

2.1.8 C语言中的逻辑运算

TRUE==》1
FALSE==》0
逻辑运算&&和||与它们对应的位级运算&和|之间第二个重要区别,如果对第一个参数求值就能确定表达式的结果,那么逻辑运算符就不会对第二个参数求值。

2.1.9 C语言中的移位运算

image.png

<<左移:该值从右开始,向左移动4位,丢弃左边最高k个数字,右边添加4个0
>>逻辑右移:左边补k个0,右边k个数字舍弃
>>算术右移:左边补k个1(注意:这里是最高位是多少填充多少),右边k个数字舍弃
默认使用算术右移,但是无符号数是逻辑右移。

2.2 整数表示

2.2.1 整数数据类型

image.png

2.2.2 无符号数的编码:

image.png

个人理解:这个公式其实就是把二进制数转成十进制数。

2.2.3 补码编码:

image.png

个人理解:简单的说就是在最高位添加了个符号位。
原理:补码编码的唯一性。

2.2.4 有符号数和无符号数之间的转换:

C语言允许在各种不同的数字数据类型之间做强制类型转换。


image.png

2.2.5 C语言中的有符号数与无符号数

尽管c语言标准没有指定有符号数要采用某种表示,但是几乎所有的机器都是用补码。通常,大多数数字都默认为是有符号的。


image.png

2.2.6 扩展一个数字的位表示

image.png

2.2.7 截断数字

截断无符号数

截断补码取值

2.2.8 关于有符号数和无符号数的建议

2.3 整数运算

个人理解:这里主要以数学公式的形式讲述了整数的运算。

2.3.1 无符号加法

image.png

image.png

2.3.2 补码加法

image.png

image.png

2.3.3 补码的非

image.png

2.3.4 无符号乘法

image.png

2.3.5 补码乘法

image.png

2.3.6 乘以常数

image.png

注意:无论是无符号运算还是补码运算,乘以2的幂都可能会导致溢出。

2.3.7 除以2的幂

image.png

image.png

image.png

2.3.8 关于整数运算的最后思考

个人理解,关于整数的相关运算规则。

2.4 浮点数

image.png

2.4.1 二进制小数

image.png

2.4.2 IEEE浮点表示

image.png

image.png

情况1:当exp的位模式既不全为0(数值0),也不全为1(单精度数组为255,双精度数值为2047)
情况2:当补码域为全0时
情况3:当指阶码全为1的时候出现

2.4.3 数字示例

image.png

image.png

2.4.4 舍入

image.png

2.4.5 浮点运算

2.4.6 C语言中的浮点数

image.png

第三章 程序的机器级表示

个人理解:该章节主要讲了汇编,我们写的c代码是如何翻译成汇编语言到机器的寄存器的,没学过汇编,前部分还好,后面看不来。

3.1 历史观点

3.2 程序编码

image.png

3.2.1 机器级代码

● 程序计数器(通常成为“PC”,在x86-64中用%rip表示)给出将要执行的下一条指令在内存中的地址。
● 整数寄存器文件包含16个命名的位置,分别存储64位的值。这些寄存器可以存储地址(对应于C语言的指针)或整数数据。有的寄存器被用来记录某些重要的程序状态,而其他的寄存器用来保存临时数据,例如过程的参数和局部变量,以及函数的返回值。
● 条件码寄存器保存着最近执行的算术或逻辑指令的状态信息。它们用来实现控制或数据流中的条件变化,比如说用来实现if和while语句。
● 一组向量寄存器可以存放一个或多个整数或浮点数值。

3.2.2 代码示例

在命令行上使用“-S”选项,就能看到C语言编译器产生的汇编代码
linux>gcc -Og -S xxx.c
使用“-C”命令行选项,GCC会编译并汇编该代码
linux>gcc -Og -C xxx.c
这样会产生目标代码文件xxx.o,它是二进制格式的,无法直接查看。要查看机器代码文件的内容,有一类成为反汇编器的程序非常有用。在Linux系统中,带“-d”命令行标识的程序OBJDUMP可以充当这个角色。
linux>objdump -d xxx.o


image.png

3.2.3 关于格式的注解

3.3 数据格式

image.png

3.4 访问信息

3.4.1 操作数指示符

大多数指令有一个或多个操作数,指示出执行一个操作中要使用的源数据值,以及放置结果的目的位置。
各种不同的操作数的可能性被分为三种类型
立即数:用来表示常数值。
寄存器:表示某个寄存器的内容。
内存引用:根据计算出来的地址访问某个内存位置。


image.png

3.4.2 数据传送指令

image.png

image.png

3.4.3 数据传送示例

image.png

3.4.4 压入和探出栈数据

image.png

3.5 算术和逻辑操作

image.png

3.5.1 有效加载地址

image.png

3.5.2 一元和二元操作

image.png

3.5.3 移位操作

image.png

3.5.4 讨论

3.5.5 特殊的算术操作

image.png

3.6 控制

3.6.1 条件码

image.png

3.6.2 访问条件码

条件码读取三种方法:
1.根据条件码的某种组合,将一个字节设置为0或者1
2.可以条件跳转到程序的某个其他的部分
3.可以有条件地传送数据。

3.6.3 跳转指令

image.png

3.6.4 跳转指令的编码

3.6.5 用条件控制来实现条件分支

将条件表达式和语句从C语言翻译成机器代码,最常用的方式是结合有条件和无条件跳转。

3.6.6 用条件传送来实现条件分支

3.6.7 循环

3.6.8 switch语句

3.7 过程

image.png

3.7.1 运行时栈

image.png

3.7.2 转移控制

image.png

3.7.3 数据传送

3.7.4 栈上的局部存储

3.7.5 寄存器中的局部存储空间

3.7.6 递归过程

3.8 数组分配和访问

第四章 处理器体系结构

4.1 Y86-64 指令集体系结构

4.1.1 程序员的可见状态

image.png

4.1.2 Y86-64指令

● x86-64的movq指令分成了4个不同的指令:irmovq、rrmovq、mrmovq、rmmovq,分别显示地指明源和目的的格式。源可以是立即数i,寄存器r或内存m。第一个字母表示源的类型,第二个字母表示目的的类型。
● 有4个整数操作指令,他们是addq、subq、andq和xorq,它们只对寄存器数据进行操作,而x86-64还允许对内存数据进行这些操作。这些指令会设置3个条件码ZF、SF和OF(零、符号、溢出)。
● 7个跳转指令,jmp、jle、jl、je、jne、jge和jg。
● 6个条件传送指令,cmovle、cmovl、cmove、comvne、cmovge和comvg。
● call指令将返回地址入栈,然后调到目的地址。
● ret指令从这样的调用中返回。
● pushq和popq指令实现了入栈和出栈。
● halt指令停止指令的执行。


image.png

4.1.3 指令编码

image.png

image.png

4.1.4 Y86-64异常

image.png

4.1.5 Y86-64程序

image.png

4.1.6 Y86-64指令的详情

image.png

4.2 逻辑设计和硬件控制语言HCL

4.2.1 逻辑门

image.png

4.2.2 组合电路和HCL布尔表达式

image.png

image.png

4.2.3 字级的组合电路和HCL整数表达式

image.png

image.png

4.2.4 集合关系

4.2.5 存储器和时钟

image.png

4.3 Y86-64的顺序实现

4.3.1 将处理组织成阶段

image.png

4.3.2 SEQ硬件结构

image.png

4.3.3 SEQ时序

4.3.4 SEQ阶段的实现

1.取指阶段


image.png

2.译码和写回阶段


image.png

3.执行阶段
image.png

4.访存阶段


image.png

5.更新PC阶段
image.png

4.4 流水线的通用原理

4.4.1 计算流水线

image.png

image.png

4.4.2 流水线操作的详细说明

image.png

4.4.3 流水线的局限性

image.png

1.不一致的划分
2.流水线过深,收益反而下降

4.4.4 带反馈的流水线系统

image.png

4.5 Y86-64流水线的实现

4.5.1 SEQ+:重新安排计算阶段

image.png

4.5.2 插入流水线寄存器

image.png

第五章 优化程序性能

5.9 提高并行性

5.9.1 多个累计变量

对于一个可结合和可交换的合并运算来说,比如说整数加法或乘法,我们可以将一组合并运算分割成两个或更多的部分,并在最后合并结果来提高性能。

5.9.2 重新结合变换

5.10 优化合并代码的结果小结

image.png

5.11 一些限制因素

5.11.1 寄存器溢出

循环并行性的好处受汇编代码描述计算的能力限制。如果我们的并行度p超过了可用的寄存器数量,那么编译器会诉诸溢出,将某些临时值存放到内存中,通常是在运行时堆栈上分配空间。
一旦编译器必须要诉诸溢出,那么维护多个累积变量的优势就很可能消失。幸运的是,x86-64有足够多的寄存器,大多数循环在出现寄存器溢出之前就将达到吞吐量限制。

5.11.2 分支预测和预测错误处罚

当分支预测逻辑不能正确预测一个分支是否要跳转的时候,条件分支可能会招致很大的预测错误处罚。

  1. 不要过分关心可预测的分支
  2. 书写适合用条件传送实现的代码

5.12 理解内存性能

5.12.1 加载的性能

5.12.1 存储的性能

5.13 应用:性能提高技术

  1. 高级设计,为遇到的问题选择适当的算法和数据结构。
  2. 基本编码原则。避免限制优化的因素,这样编译器就能产生高效的代码。
    消除连续的函数调用。
    消除不必要的内存引用
  3. 低级优化,结构化代码以利用硬件功能
    展开循环,降低开销,并且使得进一步的优化成为可能。
    通过使用例如多个累计变量和重新结合等技术,找到方法提高指令级并行。
    用功能性的风格重写条件操作,使得编译采用条件数据传送。

5.14 确认和消除性能瓶颈

5.14.1 程序剖析

第六章 存储器层次结构

6.1 存储技术

6.1.1 随机访问存储器

  1. 静态RAM:SRAM将每个位存储在一个双稳态的存储器单元里,每个单元是用一个六晶体管电路来实现的。他可以无限期地保持在两个不同的电压配置或状态之一。由于SRAM存储器单元的双稳态特性,只要有电,他就会永远地保存它的值。即使有干扰来扰乱电压,当干扰消除时,电路就会恢复到稳定值。
  2. 动态RAM
    DRAM将每个位存储为对一个电容的充电。这个电容非常小,通常只有大约30毫微微法拉——30*10-15法拉。
    3.传统的DRAM
    DRAM芯片中的单元(位)被分成d个超单元,每个超单元都由w个DRAM单元组成。一个dxw的DRAM总共存储了dw位信息。
  3. 内存模块
    DRAM芯片封装在内存模块中,它查到主板的扩展槽上。
  4. 增强的DRAM
    快页模式
    扩展数据输出
    同步DRAM
    双倍数据速率同步
    视频RAM
  5. 非易失性存储器
    非易失性存储器即使在关电之后,仍然保存着它们的信息。
  6. 访问主存

6.1.2 磁盘存储

  1. 磁盘构造


    image.png
  2. 磁盘容量


    image.png

    image.png
  3. 磁盘操作
  4. 逻辑磁盘块
  5. 连接I/O设备
  6. 访问磁盘

6.1.3 固态硬盘

image.png

6.1.4 存储技术趋势

6.2 局限性

image.png

6.2.1 对程序数据引用的局部性

6.2.2 取指令的局部性

6.2.3 局部性小结

image.png

6.3 存储器层次结构

image.png

6.3.1 存储器层次结构中的缓存

image.png

1.缓存命中
2.缓存不命中
3.缓存不命中的种类
4.缓存管理

6.3.2 存储器层次结构概念小结

[图片上传中...(image.png-534f9-1592886451099-0)]

image.png

6.4 高速缓存存储器

image.png

6.4.1 通用的高速缓存存储器组织结构

image.png

image.png

6.4.2 直接映射高速缓存

image.png

image.png

image.png

image.png

image.png

6.4.3 组相联高速缓存

image.png

image.png

image.png

6.4.4 全相联高速缓存

image.png

image.png

6.4.5 有关写的问题

image.png

6.4.6 一个真实的高速缓存层次结构的解剖

6.4.7 高速缓存参数的性能影响

image.png

image.png

image.png

6.5 编写高速缓存友好的代码

image.png

image.png

6.6 综合:高速缓存对程序性能的影响

6.6.1 存储器山

一个程序从存储系统中读数据的速率成为度吞吐量,或者有时成为读带宽。


image.png

6.6.2 重新排列循环以提高空间局部性

6.6.3 在程序中利用局部性

  1. 将你的注意力集中在内循环上,大部分计算和内存访问都发生在这里。
  2. 通过按照数据对象存储在内存中的顺序,以步长为1的来读数据,从而使得你程序中的空间局部性最大。
  3. 一旦从存储器中读入了一个数据对象,就尽可能多地使用它,从而使得程序中的时间局部性最大。

6.7 小结

image.png

第七章 链接

7.1 编译器驱动程序

大多数编译系统提供编译器驱动程序,它代表用户在需要时调用语言预处理器、编译器、汇编器和链接器。


image.png

驱动程序首先运行C预处理器,它将C的源代码翻译成一个ASCII码的中间文件,接下来,驱动程序运行C编译器,它将该文件翻译成一个ASCII汇编语言文件,然后驱动程序运行汇编器,在翻译成一个可重定位目标文件。最后,它运行链接器程序id,将一些必要的系统目标文件组合起来,创建一个可执行目标文件prog。要运行prog,只要输入./prog,shell调用操作系统中一个叫做加载器的函数,它将可执行文件prog中的代码和数据复制到内存,然后将控制转移到这个程序的开头。

7.2 静态链接

image.png

7.3 目标文件

image.png

7.4 可重定位目标文件

image.png

image.png

7.5 符号和符号表

image.png

7.6 符号解析

7.6.1 链接器如何解析多重定义的全局符号

image.png

7.6.2 与静态库链接

image.png

7.6.3 链接器如何使用静态库来解析引用

image.png

image.png

7.7 重定位

image.png

7.7.1 重定位条目

image.png

7.7.2 重定位符号引用

  1. 重定位PC相对引用
  2. 重定位PC绝对引用

7.8 可执行目标文件

image.png

7.9 加载可执行目标文件

image.png

7.10 动态链接共享库

image.png

7.11 从应用程序中加载和链接共享库

image.png

7.12 位置无关代码

  1. PIC数据引用
  2. PIC函数调用


    image.png

    image.png

    image.png

7.13 库打桩机制

image.png

7.13.1 编译时打桩

image.png

7.13.2 链接时打桩

7.13.3 运行时打桩

image.png

7.14 处理目标文件的工具

image.png

7.15 小结

第八章 异常流控制

8.1 异常

异常就是控制流中的突变,用来相应处理器状态中的某些变化。


image.png

image.png

8.1.1 异常处理

image.png

8.1.2 异常的类别

image.png

8.1.3 Linux/x86-64 系统中的异常

image.png
  1. Linux/x86-64 故障和终止
  2. Linux/x86-64系统调用


    image.png

8.2 进程

进程提供给应用程序的关键抽象
一个独立的逻辑控制流,它提供了一个假象,好像我们的程序独占地使用处理器。
一个私有的地址控件,它提供了一个假象,好像我们的程序独占地使用内存系统。

8.2.1 逻辑控制流

image.png

8.2.2 并发流

image.png

8.2.3 私有地址空间

image.png

8.2.4 用户模式和内核模式

image.png

8.2.5 上下文切换

内核为每个进程维持一个上下文,上下文就是内核重新启动一个被抢占的进程所需的状态。它由一些对象的值组成,这些对象包括通用目的寄存器、浮点寄存器、程序计数器、用户栈、状态寄存器、内核栈和各种内核数据结构,比如描述地址控件的页表、包含有关当前进程信息的进程表,以及包含进程已打开文件的信息的文件表。


image.png

8.3 系统调用错误处理

image.png

8.4 进程控制

8.4.1 获取进程ID

image.png

8.4.2 创建和终止进程

image.png

image.png

8.4.3 回收子线程

image.png
  1. 判定等待集合的成员
  2. 修改默认行为
  3. 检查已回收子进程的退出状态
  4. 错误条件
  5. wait函数
  6. 使用waitpid的示例

8.4.4 让进程休眠

image.png

8.4.5 加载并运行程序

8.4.6 利用fork和execve运行程序

8.5 信号

image.png

8.5.1 信号术语

image.png

8.5.2 发送信号

  1. 进程组
  2. 用/bin/kill 程序发送信号
  3. 从键盘发送信号
  4. 用kill函数发送信号
  5. 用alarm函数发送信号

8.5.3 接收信号

image.png

8.5.4 阻塞和解除阻塞信号

image.png

8.5.5 编写信号处理程序

  1. 安全的信号处理
  2. 正确的信号处理
  3. 可移植的信号处理

8.5.6 同步流以避免讨厌的并发错误

8.5.7 显式地等待信号

8.6 非本地跳转

image.png

8.7 操作进程的工具

image.png

8.8 小结

image.png

第九章 虚拟内存

9.1 物理和虚拟寻址

image.png

image.png

9.2 地址空间

9.3 虚拟内存作为缓存的工具

image.png

9.3.1 DRAM缓存的组织结构

image.png

9.3.2 页表

image.png

9.3.3 页命中

image.png

9.3.4 缺页

image.png

9.3.5 分配页面

image.png

9.3.6 又是局部性救了我们

9.4 虚拟内存作为内存管理的工具

image.png

9.5 虚拟内存作为内存保护的工具

9.6 地址翻译

image.png

image.png

9.6.1 结合高速缓存和虚拟内存

image.png

9.6.2 利用TLB加速地址翻译

image.png

9.6.3 多级页表

image.png

9.6.4 综合:端到端的地址翻译

9.7 案例研究:Intel Core i7/Linux 内存系统

9.7.1 Core i7地址翻译

image.png

image.png

9.7.2 Linux虚拟内存系统

image.png
  1. Linux虚拟内存区域
  2. Linux缺页异常处理

9.8 内存映射

9.8.1 在看共享对象

image.png

9.8.2 再看fork函数

image.png

9.8.3 再看execve函数

image.png

9.8.4 使用mmap函数的用户级内存映射

image.png

9.9 动态内存分配

image.png

image.png

9.9.1 malloc 和 free 函数

image.png

9.9.2 为什么要使用动态内存分配

9.9.3 分配器的要求和目标

image.png

目标1.最大化吞吐率
目标2.最大化内存利用率

9.9.4 碎片

image.png

9.9.5 实现问题

image.png

9.9.6 隐式空闲链表

image.png

image.png

9.9.7 放置已分配的块

9.9.8 分割空闲块

image.png

9.9.9 获取额外的堆内存

image.png

9.9.10 合并空闲块

9.9.11 带边界标记的合并

9.9.12 综合:实现一个简单的分配器

  1. 通用分配器设计
  2. 操作空闲链表的基本常数和宏
  3. 创建初始空闲链表
  4. 释放和合并块
  5. 分配块

9.9.13 显式空闲链表

image.png

9.9.14 分离的空闲链表

  1. 简单分离存储
  2. 分离适配
  3. 伙伴系统

9.10 垃圾收集

9.10.1 垃圾收集器的基本知识

image.png

9.10.2 Mark&Sweep垃圾收集器

image.png

9.10.3 C程序的保守Mark & Sweep

image.png

9.11 C程序中常见的与内存有关的错误

9.11.1 间接引用坏指针

9.11.2 读未初始化的内存

9.11.3 允许栈缓冲区溢出

9.11.4 假设指针和它们指向的对象是相同大小的

9.11.5 造成错位错误

9.11.6 引用指针,而不是它所指向的对象

9.11.7 误解指针运算

9.11.8 引用不存在的变量

9.11.9 引用空闲堆块中的数据

9.12 小结

第十章 系统级I/O

10.1 Unix I/O

打开文件
Linux shell创建的每个进程开始时都有三个打开的文件
改变当前的文件位置
读写文件
关闭文件

10.2 文件

普通文件包含任意数据
目录是包含一组链接的文件,其中每个链接都将一个文件名映射到一个文件,这个文件可能是另一个目录
套接字是用来与另一个进程进行跨网络通信的文件

10.3 打开和关闭文件

10.4 读和写文件

image.png

10.5 用RIO包健壮地读写

  1. 无缓冲的输入输出函数
  2. 带缓冲的输入函数

10.6 读取文件元数据

10.7 读取目录内容

10.8 共享文件

  1. 描述符表
  2. 文件表
  3. v-node表

10.9 I/O重定向

10.10 标准I/O

image.png

10.11 综合:我该使用哪些I/O函数?

10.12 小结

第十一章 网络编程

11.1 客户端-服务端编程模型

image.png

11.2 网络

image.png

11.3 全球IP因特网

image.png

11.3.1 IP地址

11.3.2 因特网域名

11.3.3 因特网连接

11.4 套接字接口

image.png

11.4.1 套接字地址结构

image.png

11.4.2 socket函数

image.png

11.4.3 connect函数

image.png

11.4.4 bind函数

image.png

11.4.5 listen函数

image.png

11.4.6 accept函数

image.png

11.4.7 主机和服务的转换

  1. getaddrinfo函数
  2. getnameinfo函数

11.4.8 套接字接口的辅助函数

  1. open_clientfd函数
  2. open_listenfd函数

11.4.9 echo客户端和服务端的示例

11.5 Web服务器

11.5.1 Web基础

image.png

11.5.2 Web内容

11.5.3 HTTP事务

1.HTTP请求
2.HTTP响应

11.5.4 服务动态内容

  1. 客户端如何将程序参数传递个服务器
  2. 服务端如何将参数传递给子进程
  3. 服务器如何将其他信息传递给子进程
  4. 子进程将它的输出发送到哪里

11.6 综合:TINY Web服务器

11.7 小结

第十二章 并发编程

12.1 基于进程的并发编程

12.1.1 基于进程的并发服务器

image.png

12.1.2 进程的优劣

image.png

12.2 基于I/O多路复用的并发编程

12.2.1 基于I/O多路复用的并发事件驱动服务器

image.png

12.2.2 基于I/O多路复用的优劣

优点1. 它比基于进程的设计给了程序员更多的对程序行为的控制
优点2. 一个基于I/O多路复用的事件驱动服务器是运行在单一进程上下文中的,因此每个逻辑流都能访问该进程的全部地址控件。这使得在流之间共享数据变得很容易。
优点3. 事件驱动设计常常比基于进程的设计要高效得多,因为它们不需要进程上下文切换来调度新的流。
缺点:编码复杂,随着并发粒度的减小,复杂性还会上升。

12.3 基于线程的并发编程

12.3.1 线程执行模型

image.png

12.3.2 Posix线程

12.3.3 创建线程

12.3.4 终止线程

  1. 当顶层的线程例程返回时,线程会隐式地终止
  2. 通过调用pthread_exit函数,线程会显式地终止。
  3. 某个对等线程调用Linux的exit函数,该函数终止进程以及所有与该进程相关的线程。
  4. 另一个对等线程通过以当前 线程ID作为参数调用pthread_cancel函数来终止当前线程。

12.3.5 回收已终止线程的资源

12.3.6 分离线程

image.png

12.3.7 初始化线程

image.png

12.3.8 基于线程的并发服务器

12.4 多线程程序中的共享变量

12.4.1 线程内存模型

image.png

12.4.2 将变量映射到内存

  1. 全局变量
  2. 本地自动变量
  3. 本地静态变量

12.4.3 共享变量

image.png

12.5 用信号量同步线程

12.5.1 进度图

12.5.2 信号量

image.png

12.5.3 使用信号量来实现互斥

12.5.4 利用信号量来调度共享资源

  1. 生产者-消费者的问题
  2. 读者-写者问题

12.5.5 综合:基于预线程化的并发服务器

12.6 使用线程提高并发性

image.png

12.7 其他并发问题

12.7.1 线程安全

四个线程不安全函数类

  1. 不保护共享变量的函数。
  2. 保持跨越多个调用的状态的函数。
  3. 返回指向静态变量的指针的函数。
  4. 调用线程不安全函数的函数。

12.7.2 可重入性

12.7.3 在线程化的程序中使用已存在的库函数

12.7.4 竞争

image.png

12.7.5 死锁

信号量引入了一种潜在的令人厌恶的运行时错误,叫做死锁。它指的是一组线程被阻塞了,等待一个永远也不会为真的条件。


image.png

12.8 小结

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342