概述
程序员的自我修养
此书正在阅读中,笔记持续更新。。。
回顾
1、线程
(1)什么是线程
- 轻量级进程
- 由线程ID、当前指令指针、寄存器集合、堆栈组成
一个进程由一个到多个线程组成,各个线程之间共享程序的内存空间(包括代码段、数据段、堆等)以及一些进程级的资源(如打开文件和信号)
(2)单线程 & 多线程
① 使用多线程的原因
② 多线程模型
- 一对一
- 多对一
- 多对多
(3)线程调度及优先级
① 状态切换
抢占:线程在用尽时间片后会被强制剥夺继续执行的权利,而进入就绪状态,分为可抢占线程和不可抢占线程
② 优先级
a. 分类
- IO密集型线程:频繁等待的线程
- CPU密集型线程:很少等待的线程
b. 饿死
c. 线程优先级改变的方式
- 用户指定优先级
- 根据进入等待状态的频繁程度提升或降低优先级
- 长时间得不到执行而被提升优先级
(4)线程安全
① 单指令的操作成为原子的,器质性是不会被打断的
② 同步:一个线程访问数据为结束的时候,其他线程不得对同一个数据进行访问 -> 对数据的访问被原子化了
- 锁:非强制机制
- 二元信号量
- 状态:占用、非占用
- 多元信号量,即信号量
case:一个初始值为N的信号量允许N个线程并发访问
① 获取信号量
② 操作过程:
- 信号量-1
- 信号量<0,进入等待状态;否则继续执行
③ 访问玩资源,线程释放信号量的操作: - 信号量+1
- 信号量<1, 唤醒一个等待中的线程
- 互斥量
- 临界区
- 读写锁
③ 可重入
a. 情况:
- 多个线程同时执行该函数
- 函数自身调用自身(可能经过多层调用)
b. 条件:
- 不使用任何(局部)静态或全局的非const变量
- 不返回任何(局部)静态或全局的非const变量指针
- 仅依赖调用方提供的参数
- 不依赖任何单个资源的锁(mutex等)
- 不调用任何不可冲入的函数
静态链接
Build:包含编译和链接,IDE和编译器提供的默认配置、变异和连接参数对于大部分的应用程序开发已足够使用,那么实际的系统软件的运行机制和原理是怎么样的呢
分为四个步骤:预处理、编译、汇编、链接
1、预编译
主要处理以“#”开头的预编译指令,如:“#include”、“#define”,得到预编译文件(.i/.ii)
2、编译
将预编译文件进行词法分析、语法分析、语义分析以及优化
,生成汇编代码文件(.s)
编译6步骤:扫描、语法分析、语义分析、源代码优化、代码生成和目标代码优化
举个例子:
// CompilerExpression.c
array[index] = (index + 4) * (2 + 6)
① 扫描:源程序输入扫描器,将源代码字符序列分割成一系列记号
② 语法分析:采用语法上下文无关语法,对记号进行语法分析,产生语法树(以表达式为节点的树)
③ 语义分析:静态语义、动态语义
④中间语言生成:类型根据编译器,主要有:三地址码、P-代码
t1 = 2 + 6
t2 = index + 4
t3 = t2 * t1
array[index] = t3
优化之后:
t2 = index + 4
t2 = t2 * 8
array[index] = t2
编译器前端:产生机器无关的中间代码
编译器后端:将中间代码转换成目标机器代码
3、汇编
将汇编代码转变为机器码
(1)目标代码生成与优化
其中,编译器后端
- 代码生成器:将中间代码转换成目标机器代码
- 目标代码优化器:比如选择合适的寻址方式、使用位移来代替乘法运算、删除多余
movl index, %ecx; value of index to ecx
addl $4, %ecx; ecx = ecx + 4
mull $8, %ecx; ecx = ecx * 8
movl index, %eax; value of index to eax
movl %ecx, array(, eax, 4); array[index] = ecx
乘法由一条相对复杂的基址比例变址寻址的lea指令完成,mov指令完成赋值
4、链接
(1)生成可执行文件(最常见为运行时库:支持程序运行的基本函数的集合)
(2)重定位入口
(3)链接主要过程:
- 址和空间分配
- 符号决议
- 重定义
装载与动态链接
库与运行库
最后
以上就是明理诺言为你收集整理的程序员的自我修养 --- 链接、装载与库程序员的自我修养的全部内容,希望文章能够帮你解决程序员的自我修养 --- 链接、装载与库程序员的自我修养所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复