系统基础复习1
- 进程/线程/协程
进程:一个执行中程序的实例,系统中的每个程序都运行在某个进程的上下文中进程是系统资源分配的最小单位
进程出现的目的:更好的利用CPU资源
a) A执行任务(读取数据)的时候,让B执行任务,当A读取完数据后,再“切换”回A任务
b) 切换涉及到状态的保存和恢复,因此通过进程来分配资源,标识任务
c) 分配CPU去执行进程称之为调度,进程的状态保存、恢复、上下文切换
线程:运行在进程上下文中的逻辑流
线程是CPU调度的最小单位
线程出现的目的:共享进程资源,减少上下文切换的损耗
a) AB任务拥有共同需要的系统资源
协程:程序之间的切换由用户自行处理,可以是大型程序中的某段代码,
协程是用户级别的CPU调度
线程出现的目的:避免陷入内核级别的上下文切换造成性能上的损失
a) 高并发场景,存在线程处于等待状态的情况
b) 进程/线程都是操作系统自带的;协程由程序原生支持
核心:线程是内核态调度,协程是用户态调度
- 上下文切换
- 在切换过程中:首先要存储当前进程状态(包括内存空间指针,执行完的指令等等),读入下一个进程的状态,然后执行次进程
- 为什么进程上下文切换比线程上下文切换代价高?
- 进程切换分为两个步骤:
1. 切换页目录以使用新的地址空间
2. 切换内核栈和硬件上下文
- 对于线程来说只需要执行第2步,对于进程来说要执行12步
- 进程和线程都是CPU工作时间段的描述,只不过是颗粒度不同;因为线程共享进程的上下文,所以是更细的CPU时间段描述
- 进程就是包换上下文切换的程序执行时间总和 = CPU加载上下文+CPU执行+CPU保存上下文
- 进程类型
- 孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,这些子进程称为孤儿进程。
(孤儿进程将由 init 进程收养并对它们完成状态收集工作)
- 僵尸进程
原因: 子进程exit()退出后,父进程没有对其进行回收(调用wait()或waitpid()函数),导致子进程占用的资源没有释放从而成为僵尸进程
解决:
1. 当使用top命令的时候关注zombie信息
2. ps -elf | grep Z 找到对应的僵尸进程
3. kill -9 P_pid 杀死僵尸进程的父进程;让子进程由Init进程回收
如何避免:
1. 父进程wait()或waitpid()等待子进程结束
2. Singal信号:当子进程exit()后,发送信号给父进程,父进程调用wait()
3. Singal信号:将信号直接发往内核,由内核直接回收
4. fork()两次:子进程exit()后,孙进程由Init进程回收
- 进程/线程间通信方式
- 进程通信方式:管道/消息队列/信号量/共享存储/信号量:是一个计数器,可以用来控制多个进程对共享资源的访问,交换的信息量较少也称之为低级进程通信
管道:单向,先进先出,无格式的,固定大小的字节流,它把一个进程的标准输出和另一个进程的标准输入连接在一起
消息队列:是一个在系统内核中用来保存消 息的队列,它在系统内核中是以消息链表的形式出现的。
消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点
共享存储:允许多个进程访问同一个逻辑内存,这个逻辑内存可以被多个进程映射到自身的内存地址空间中,是最快的IPC通信方式;
专门针对其他底层进程通信方式来设计的,通常配合信号量完成进程的通信和同步
套接字:可用于不同主机上进程之间的通信
- 线程通信方式:同一进程下的线程共享数据(比如全局变量,静态变量),通过这些数据来通信不仅快捷而且方便,所以主要作用是线程同步问题:
🔒机制:互斥锁/条件变量/读写锁
信号机制
信号量机制
- 进程调度
- 调度种类:- 作业调度:决定把后背作业调入内存中运行
- 进程调度:决定把就绪队列的某个进程获得CPU
- 虚拟存储中引入调度:在内外对换区进行进程对换
- 非抢占调度和抢占调度:
- 非抢占调度:一旦分配CPU给进程便让其一直运行,直到进程完成/发生进程调度某个事件而堵塞时,才会把CPU分配给其他进程
- 抢占调度:操作系统将正在运行的进程暂停,由调度程序将CPU分配给其他就绪进程的调度方式
- 调度策略设计:
- 响应时间:用户输入到产生反应的时间
- 执行时间:从任务开始到任务结束的时间
- 调度算法:
- FIFO: 先来先调度
- SJP: 最短的作业(CPU区间长度最小)最先调度
- SRJP: SJP的抢占版本
- 优先权调度:优先级最高的任务最先调度
- 轮询调度
- 多级队列调度
- 多级反馈队列调度:
a) 进程在进入待调度的队列等待时,首先进入优先级最高的Q1等待
b) 首先调度优先级高的队列中的进程。若高优先级中队列中已没有调度的进程,则调度次优先级队列中的进程。
c) 对于同一个队列中的各个进程,按照时间片轮转法调度
d) 在低优先级的队列中的进程在运行时,又有新到达的作业,那么在运行完这个时间片后,CPU马上分配给新到达的作业(抢占式)
- Linux网络IO模式
同步:执行一个操作后,等待结果,然后才执行后续操作异步:执行一个操作后,可以继续执行其他操作,等待通知再来执行刚才没执行完的操作
阻塞:进程给CPU传达任务后,一直等待CPU处理完后,然后执行后续操作
非阻塞:进程给CPU传达任务后,继续执行后续操作,隔断时间再来询问之前的操作是否完成
- IO多路复用
https://www.cnblogs.com/aspirant/p/9166944.html
- copy-on-write技术
https://blog.csdn.net/weixin_39554266/article/details/82835478
- 线程安全:全局变量和静态变量引起
- 若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;
- 若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。
- 线程共享资源和独占资源问题
- 堆:是大家共有的空间,分全局堆和局部堆。
a) 全局堆就是所有没有分配的空间
b) 局部堆就是用户分配的空间。
- 堆在操作系统对进程初始化的时候分配,运行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就是内存泄漏
- 栈:是个线程独有的,保存其运行状态和局部自动变量的。
a) 栈在线程开始的时候初始化,每个线程的栈互相独立,因此,栈是thread safe的
b) 操作系统在切换线程的时候会自动的切换栈,就是切换 SS/ESP寄存器
- 操作系统相关知识点:https://www.cnblogs.com/inception6-lxc/p/9073983.html
- TCP最大连接数
- TCP最大连接数的影响因素: 内存和文件描述符
-文件描述符: 每个tcp连接都会占用一个文件描述符,操作系统对最大文件数有限制
- 单个进程能够打开的文件数量默认上限为1024
[root@test ~]# ulimit -n
1024
- 临时修改: ulimit -n xxxxx
- 重启后失效的修改:
配置文件:/etc/security/limits.conf
soft nofile 1000000
hard nofile 1000000
- 永久修改:/etc/rc.local文件中加入
ulimit -SHn 1000000
- 全局限制:
[root@test ~]# cat /proc/sys/fs/file-nr
992 0 95146
已经分配的文件句柄数 已经分配但没有使用的句柄数 最大文件句柄数
调整相关值:/etc/sysctl.conf
fs.file-max = 1000000 # 最大文件句柄数
net.ipv4.ip_conntrack_max = 1000000
net.ipv4.netfilter.ip_conntrack_max = 1000000
- 高并发Web服务器内核参数调优:
net.ipv4.tcp_syncookies = 1 # 预防少量SYN攻击
net.ipv4.tcp_tw_reuse = 1 # 开启重用(timewait)
net.ipv4.tcp_tw_recycle = 1 (不推荐,NAT下会产生大量的timeout) #开启tcp快速回收(timewait)
net.ipv4.tcp_fin_timeout = 30 # 处于fin_wait_2状态的时间
net.ipv4.tcp_max_syn_backlog=65536 #SYN队列长度
net.core.somaxconn=32768 # listen()的默认参数,挂起请求的最大数量
net.core.netdev_max_backlog=65536 # 进入包的最大数量即:三次握手之后的连接
sysctl -w net.ipv4.ip_conntrack_max=65536
内核参数博客:https://blog.csdn.net/sa19861211/article/details/90237203