进程和线程

  • 进程: 随着程序运行, 所需的全部状态信息(程序代码本身, 数据, 状态信息)
Pid数目:0~32767,因为进程号是short int类型,一般来说,OS倾向先分配未使用过的,因此一般pid比较大,当然如果用到32767了,之后就会重新分配未被使用过的最小的进程号
  • PCB: OS为每个进程都维护一个PCB(进程控制块), 用于保存该进程有关的所有状态信息
PCB维护的进程信息:
1.进程标识信息: 本进程的pid, 父进程的pid, 用户标识
2.处理机状态信息保存区: 用于保存进程的运行现场信息, PC保存进程执行到哪了, 以及ESP, EBP表示当前的栈帧状态等
3.进程控制信息:![](https://img-blog.csdnimg.cn/20210525205937684.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppdXJpMTAwNQ==,size_16,color_FFFFFF,t_70)
  • 进程状态: 创建, 就绪, 运行, 阻塞, 结束, 以及各种挂起(就绪挂起, 运行挂起, 阻塞挂起)
  • 状态队列: 操作系统将所有处于同一状态的进程放入同一个状态队列(例如就绪队列, 阻塞队列等), 当进程状态发生转换时, 要相应调整所属的状态队列
  • 线程 = 进程 - 共享资源: OS中最小的能独立运行的基本单位, 线程是进程中的一条执行流程.
优点: 一个进程中可以同时存在多个线程, 可以并发执行, 线程之间共享相同的地址空间和文件等资源
缺点:  安全性低, 若一个线程破坏了共享资源, 则其他线程访问这些资源同样可能会崩溃

在这里插入图片描述

  • 同一进程内的不同线程共享代码段, 数据段, 文件 ,但维护各自的PC, 栈指针ESP, EBP等各种寄存器等用于线程自身的控制流相关的信息(例如程序计数器PC: 用于控制各自的运行指令), 因为线程只是运行在进程环境下的一条执行流程, 因此只需要维护与执行相关的信息即可
    在这里插入图片描述
  • 进程和线程的区别:
1.进程是资源分配的单位(包含内存, 打开的文件, 访问的网络等), 线程是CPU调度的单位(主要是控制流相关的信息)
2.进程拥有一个完整的资源平台, 而线程只独享自己必须的资源(例如各种寄存器和栈)
3.线程同样具有就绪, 阻塞, 运行三种状态, 同样具有状态间的转换关系

线程能减少并发执行的开销: 
1.线程创建和终止的时间比进程短: 对于一个进程内的线程来说, 直接重用进程的共享资源, TLB内容比PCB更少
2.同一进程内的不同线程切换时间比不同进程之间切换快: 由于同一进程内的不同线程共享地址空间, 因此所访问的页表都是相同的, 无需像进程切换一样切换新的页表(可能导致缺页中断而引发的页的换入换出)
3.同一进程的各线程之间共享内存和文件资源, 因此可以不通过内核进行IPC, 可以直接访问
  • 线程的实现:
1.用户线程:在用户空间实现, 由线程库管理, OS看不到线程信息
![用户线程的解释](https://img-blog.csdnimg.cn/20210525222836335.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppdXJpMTAwNQ==,size_16,color_FFFFFF,t_70)
缺点: ![用户线程缺点](https://img-blog.csdnimg.cn/20210525223443162.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppdXJpMTAwNQ==,size_16,color_FFFFFF,t_70)
2.内核线程:在内核实现, TCB放在内核中, 由OS管理, 粒度更小一些, 但每发生一次线程切换, 都需要进行用户态到内核态的切换, 因此开销更大
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210525224013213.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppdXJpMTAwNQ==,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210525223956988.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppdXJpMTAwNQ==,size_16,color_FFFFFF,t_70)
3.轻量级进程:一个进程可以有多个轻量级进程, 每个进程由一个单独内核线程来支持
  • context switch(上下文切换): 不同进程轮流占据CPU执行, 当一个进程的时间片结束, 将当前CPU中该进程用到的各种寄存器的值保存在该进程的PCB中, OS根据调度算法, 从就绪队列中取出下个进程的PCB, 并将其更新到CPU中去, 完成切换
  • fork: 复制父进程的虚拟地址空间给子进程, 但子进程中的虚拟地址空间的内核区中的pid,ppid等信息不同,其余信息几乎相同。
  • exec函数族: 把当前进程的内存空间中的用户区替换成指定可执行文件的用户区, 调用成功后不会返回,因为原来的代码段,数据段等等都替换成了新的内容,因此返回值没有意义。但内核区不会变,因此内核区中的PCB仍然是旧进程的,即pid, ppid, 打开的文件描述符表等等都是旧的,对外界来说就像金蝉脱壳,然后从新程序的main开始执行。只有当调用失败时才会返回-1,且从旧程序的调用点继续执行。
    在这里插入图片描述
几乎fork和exec是紧接着调用的, 而exec会把新程序的代码段, 数据段, 堆栈等信息加载进去, 因此fork所做的工作就白废了

解决: 
在fork中使用copy on write技术, 当调用fork时, 不会立刻复制一份内存给子进程, 而是只复制页表, 等到子进程真正进行写操作时, 才根据页表把所需的那部分内存复制过来
  • wait: 父进程用于等待子进程结束, 并且由父进程回收子进程的全部资源(包括用户态中的内存和内核中的PCB)
子进程不能自己回收自己的全部资源: 因为即便通过PCB把用户态的各种资源(代码段, 数据段, 堆栈等)释放掉, 但是子进程存在的唯一标识:PCB仍然存在内核中, 因此此刻该进程处于用户态资源都被回收, 但PCB还在, 相当于一个人拎着自己的头把自己拎起来, 因此回收子进程资源的事情由父进程做

父进程调用wait会使其进去睡眠状态, 等到子进程调用exit时, OS解锁父进程, 并且得到子进程exit的返回值, 由父进程回收子进程的资源
  • exit:
![在这里插入图片描述](https://img-blog.csdnimg.cn/2021052621232866.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppdXJpMTAwNQ==,size_16,color_FFFFFF,t_70)
  • 孤儿进程:
    父进程的生存期结束了,它的子进程还没结束,因此子进程的PCB就没人能回收了。OS一旦发现孤儿进程,就会将其父进程设为init进程( 其pid=1,是OS的第一个进程,后续的所有进程都是它的子孙),由init回收孤儿进程的资源。孤儿进程本身没什么危害。

  • 僵尸进程:

子进程结束, 但其父进程并未通过wait或waitpid回收其资源

危害:
主要是一直占用进程号,可能导致OS无法创建新进程

解决办法:
1.杀死父进程,这样子进程就会变成孤儿,就会由init进程回收资源
2.父进程调用wait()waitpid()

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值