题前:30--45天读完,一周至少3篇读书笔记。不能坚持,不再联系,不再找你。
一. hello world 程序引出的问题,看40天后,再回来看看自己的答案,提升多少。
Q1:程序为什么要被编译器编译之后才可以运行?
A1 : 系统执行的机器语言,即二进制文件,程序是文本文件需要编译之后,由链接器链接需要的基本库生成二进制文件.
Q2: 编译器在把C语言程序转换成可以执行的机器码的过程中作了什么,怎么做的?
A2: 预处理,汇编器生成汇编文件,编译器生成目标文件,链接器链接生成可执行文件
Q3: 最后编译的可执行文件里是什么?除了机器码还有什么?它们怎么存放的,怎么组织的?
A3: 可执行文件里面是机器码,除了机器码还有什么? 未知。 组织: bss,data, code,这个遗忘了
Q4: #include<stdio.h>是什么意思? 把stdio.h包含进来意味着什么?C语言库又是什么?它是怎么实现的?
A4: 在预处理时,会把stdio.h头文件里的程序语句加到源文件里。把stdio.h包含进来意味着可以使用在stdio.h里声明的库函数。
C语言库是为了方便程序员,而提供的基本的诸如I/O,字符处理的库函数. 怎么实现?通过动态或静态编译实现的.不知对否.
Q5: 不同的编译器和不同的硬件平台以及不同的操作系统,最后编译的结果一样吗?为什么?
A5: 不同的编译器因为处理(具体什么处理,不清楚)不同,所以接过不一样;不同的硬件平台因为指令结构不同,处理接过也不一样;
不同的操作系统因为二进制格式不一样,所以编译出来的接过不一样.
Q6: Hello World是怎么运行起来的?操作系统是怎么装载它的?它从哪儿开始执行,到那儿结束?main函数之前发生了什么?main函数结束以后发生什么?
A6: 操作系统加载到内存,找到程序入口地址,开始运行;怎么装载,未知;起于何处,至于何处未知?main函数前后发生什么未知.
Q7: 如果没有操作系统, Hello World可以运行吗?如果要在一台没有操作系统的机器上运行Hello World需要什么?应该怎么实现?
A7: 需要去掉可执行程序的头部格式(具体怎么做,忘了),然后在处理程序的时候指定加载内存的addr,然后加载到这个addr,执行。
Q8: printf 是怎么实现的?它为什么可以又不定数量的参数?为什么它能够在终端上输出字符串?
A8: printf 是通过调用系统调用write实现的,不定数量的参数依赖于stdarg.h,具体实现未知,因为终端输出也是作为文件描述符处理。
Q9: Hello World 程序在运行时,它在内存中是什么样子的?
A9: 应该是映射在物理内存的一块地方,未知.
通过回答这些问题,自己才意识自己基础多么薄弱.
二. 计算机系统软件体系结构采用一种层的结构
“Any proble in computer science can be solved by another layer of indirection."
这让自己之前写的一个线程池,朋友看后鄙视我好久,认为内聚性太低,当时我承认,可我也同时儿认为我这通用性强。
我那线程池不能作为一个接口,所以只能算dogshit.
三. 为什么要分段分页
解决内存使用的三个问题:
1. 地址空间不隔离
2. 内存使用率低
3. 程序运行地址不确定
分段通过虚拟地址映射,解决1,3
分页解决2
四. 线程基础
一个标准的线程由线程ID,当前指令指针,寄存器集合和堆栈组成。共享(代码段,数据段,堆,以及一些进程极资源)
分类: I/O密集型线程,CPU密集型线程。前者一般优先级高
优先级改变方式:
1. 用户指定优先级
2. 根据进入等待状态的频繁程度提升或降低优先级
3. 长时间得不到调度提升
五. 线程安全
1. 线程同步
原子操作,锁(二元信号量,互斥量,临界区,读写锁,条件变量)
信号量在整个系统中可以贝任意线程获取并释放,互斥量只能被获取的线程释放;临界区的作用范围仅限于本进程,互斥量在系统任何进程中可见,
除此,具有相同性质;条件变量类似与一个栅栏,线程可以一次唤醒一个或所有等待线程。应用如:线程池
2. 可重入与线程安全
@1:线程可重入情况:
多个线程同时执行这个函数
函数自身(可能经过多层调用之后)调用自身。
@2:可重入条件:
不使用任何(局部)静态或全局的非const变量
不返回任何(局部)静态货全局的非const变量
仅依赖调用方提供的参数
不依赖任何单个资源的锁
不调入任何不可重入的函数
3. 过度优化
@1: 保护区域数据因编译过度优化,存放到寄存器中
@2:编译器为了提高效率,调整两条互不影响相邻指令的执行顺序
使用volatile可以组织变量缓存到寄存器而不被写回,也可以组织编译器调整操作volatile变量的指令顺序,但不能阻止CPU动态调度程序.
C++ new的两个步骤:分配内存,调用构造函数
六. 线程模型
1. 一对一模型
2. 多对一模型
3 .多对多模型
linux 内核线程和用户线程?