- 进程/线程/协程

进程:一个执行中程序的实例,系统中的每个程序都运行在某个进程的上下文中
进程是系统资源分配的最小单位
进程出现的目的:更好的利用CPU资源
    a) A执行任务(读取数据)的时候,让B执行任务,当A读取完数据后,再“切换”回A任务
    b) 切换涉及到状态的保存和恢复,因此通过进程来分配资源,标识任务
    c) 分配CPU去执行进程称之为调度,进程的状态保存、恢复、上下文切换

线程:运行在进程上下文中的逻辑流
线程是CPU调度的最小单位
线程出现的目的:共享进程资源,减少上下文切换的损耗
    a) AB任务拥有共同需要的系统资源

协程:程序之间的切换由用户自行处理,可以是大型程序中的某段代码,
协程是用户级别的CPU调度
线程出现的目的:避免陷入内核级别的上下文切换造成性能上的损失
    a) 高并发场景,存在线程处于等待状态的情况
    b) 进程/线程都是操作系统自带的;协程由程序原生支持

核心:线程是内核态调度,协程是用户态调度

- 上下文切换

- 上下文切换:同一时刻只能执行一条CPU指令,上下文切换是指:将CPU资源从一个进程分配给另一个进程的机制
    - 在切换过程中:首先要存储当前进程状态(包括内存空间指针,执行完的指令等等),读入下一个进程的状态,然后执行次进程

- 为什么进程上下文切换比线程上下文切换代价高?
    - 进程切换分为两个步骤:
        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多路复用

- select/poll/epoll
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