一、进程
1、三种状态:运行态、就绪态、阻塞态
2、PCB表项:程序计数器、堆栈指针、内存分配、文件状态、调度信息等
3、系统初始进程
pid 0: idle 初始进程(swapper)
pid 1: init 用户态祖进程
pid 2: kthreadd 内核态祖进程
二、线程
1、用户态线程(用户级线程):线程表在用户态,由进程模拟操作系统对进程的调度来调度线程
优点:管理开销小(创建销毁不需要系统调用),切换成本低(不需要操作系统调度)
缺点:与内核协作、线程间协作成本高,无法利用多核CPU,操作系统无法对线程调度进行优化
2、核心态线程(内核级线程):线程表在内核态,由内核进行调度
优点:利用多CPU优势、操作系统调度优化
缺点:创建和销毁的开销比较大、扩展性差(管理数量有限)、切换成本高
linux采用的模型是核心态线程多对多模型,即为用户态多线程分配CPU核数的内核态线程,即减少了内核线程管理开销、又保证了多核心并发
3、线程拥有资源:程序计数器(记录需要执行的下一条指令)、寄存器(保存正在使用的变量)、堆栈(记录程序执行路径)
三、进程和线程区别
守护进程:脱离控制终端、后台运行周期性执行或处理任务、大多服务都是守护进程、利用deamon和fork创建父进程退出、特殊的孤儿进程
线程安全:操作原子性、执行有序性、利用同步机制、volatile修饰全局变量
死锁:线程A和B加锁后竞争对方持有的临界区资源
避免死锁:顺序加锁、避免一次执行加多个锁、避免单个锁占用过多临界区资源
线程池:调度更快、节省资源、单任务处理时间短、任务量大时使用
四、进程间通信
五、线程间通信
六、数据I/O
1、I/O基本原理
内存原理:用户态I/O依赖于内核接口read/write,read函数将内核缓冲区数据复制到进程缓冲区(每个进程都有独立的缓冲区),write相反,用户程序读写时大多数情况都是读写自己的进程缓冲区,实际的I/O由内核控制
同步阻塞I/O底层实现:调用accept、recv,用多线程服务于多客户端请求,多线程切换消耗CPU资源
同步非阻塞I/O底层实现:调用accept、recv不阻塞,用户线程立即返回,需要循环调用recv,消耗CPU资源
2、I/O多路复用
概念:一个线程检测多个I/O操作
实现原理:一次将多个socket连接传入内核阻塞,由内核轮询,当一个或多个socket事件发生,返回事件列表,用户进程遍历处理有事件的socket,避免多个调用recv以及用户和内核态切换
七、进程内存空间
进程的虚拟内存空间从低地址向高地址依次为:代码区 -> 常量区 -> 数据区(.bss、.data) -> 堆区 -> 栈区
八、原子操作和锁
原子操作:不能被打断的操作,单核时一条指令就是原子操作,多核时不一定
复杂操作(读文件、socket、系统调用等)可以使用mutex
操作简单且原子操作(atomic)不支持的使用spinlock
CPU指令集支持的可以使用原子操作
九、内存对齐
平台原因:有些CPU可以访问任意地址,有些只能在特定地址访问数据,不同的硬件平台有差异,在编译时将分配的内存进行对齐以空间换时间(32位默认4,,6位默认8),就可以跨平台移植
性能原因:尽可能往自然边界上对齐,防止CPU对未对齐的内存需要做两次访问
十、大小端
小端模式:高字节内容存放在高地址,低字节内容存放在低地址,计算机读取是从高地址开始的
大端模式:高字节内容存放在低地址,低字节内容存放在高地址,计算机读取是从低地址开始的
指针法:
int a = 1;
if ((char *)&a == 1)
小端;
else
大端;
共用体法:
union test {
char a,
short b;
} c;
c.b = 1;
if (c.a == 1)
小端;
else
大端;