目录
进程与线程
我们的电脑上都有应用程序,当我们双击使它运行起来时,就创造了一个进程.
进程就是正在运行的程序(如图)
进程也可以叫做一个任务(task)
进程中包括一个或多个线程
把进程比作一个工厂,线程就是进程中的流水线.
操作系统如何管理线程
- 先描述一个进程,明确进程中的一些相关属性(创造一个结构体)
- 再组织若干个进程,(使用双向链表,把很多进程的信息放到一起)
在操作系统中描述进程的这种结构体叫做PCB.
注意,上面描述的时Linux的情况,因为Windows不开源,不知道内部结构
PCB中的一些属性
上面讲到了进程有很多属性,操作系统将这些属性打包为一个结构体就是PCB
下面列举一下有哪些属性
- pid, 就是进程的身份标识,就像进程的身份证号一样
- 内存指针,指明了这个进程要执行的代码在内存中的位置,以及这个进程所依赖的数据的具体位置
- 文件描述符表,进程也会和文件打交道,文件位于硬盘上,进程每打开一个文件,就会在文件描述符表上增加一项该文件的信息(此表就像一个数组,数组元素就是一个结构体,存放着文件的信息).这里注意进程只要一启动,就会默认打开三个文件,标准输入(System.in),标准输出(System.out)和标准错误(System.err)
上面这些是一些基础的属性,下面的属性是为了能够实现进程调度:
仅通过我们8核的计算机要去完成几百个进程同时进行,这里就多亏了进程调度,也多亏下面的属性:
1. 状态 : 描述进程接下来应该如何调度(下面是最常见的两种)
- 就绪状态: 随时可以去CPU上执行
- 阻塞/睡眠状态:暂时不可以去CPU执行
2. 优先级 : 先给谁分配,或者分配多少
3. 记账信息 : 统计每个进程分别被执行多久,等了多久,还有都执行了哪些指令.用来给进程调度提供指导依据
4. 上下文:记住上次进程被调出CPU时程序的执行状态(存档),下次此进程再上CPU时就可以继续往下执行(读档).
内存资源的分配
一台电脑会运行多个进程,如果一个进程挂了,会不会影响其他进程呢?
答案是当然不会,这里依赖于每个进程有自己的"虚拟地址空间",隔离了每个进程,保证了线程的独立性.
但是也不能完全隔离,进程间也需要通信
进程之间会有一个公共空间,进程A把数据先放到此空间中,进程B就可以不接触A而拿到数据
现在最主要的使用的进程间通信方式主要有两种:文件操作和网络操作(socket)
关于线程的那些事
既然有了进程能进行多任务来"并发编程",为什么要有线程呢?
如果我们需要频繁创建/销毁进程或者调度进程,此事成本较高
创建进程会分配内存和文件资源,销毁也要释放资源,因此十分低效
那么如何解决此问题?
- 进程池. 我们可以把即将要释放的进程放到池子里,这样下次再用此进程直接可以从池子中取出, 但是闲置的进程也会浪费内存,所以此方法有缺陷.
- 使用线程实现并发编程. 线程比进程更轻量,线程也可以并发编程.进程重在需要申请资源,而线程轻就轻在共用一份进程的资源,减少了申请释放资源的过程.(就好比进程就像车间,线程就是流水线,制造一个流水线的成本远小于制造一个车间)
当然,线程也不是越多越好,因为共用一份资源,所以整体速度会下降.
总结:
下面列出一些问题, 来总结上面的内容:
1. 进程是啥?
- 跑起来的程序
2. 进程是怎样管理的?
- 描述进程属性 --> 双向链表连接
3. 进程的PCB里有啥?
- pid 内存指针 文件描述符表
4. 进程的调度是如何进行的?
- 状态 优先级 记账信息 上下文
5. 进程的独立性是咋回事?
- 虚拟地址空间
6. 进程之间如何通信?
- 公共空间
7. 谈谈线程与进程的区别与联系?
- 进程包含线程,一个进程里可以有一个线程,也可以有多个线程
- 进程和线程都是为了处理并发编程,但是进程在频繁创建和释放效率低,而线程更轻量,少了申请释放资源的过程
- 操作系统创建进程,要给进程分配资源,进程是操作系统分配资源的基本单位.而操作系统的线程,是要在CPU上调度执行,线程是操作系统调度执行的基本单位
- 进程具有独立性,每个进程有各自独立的虚拟地址空间,一个进程挂了,不会影响其他的进程.而线程共用了一个内存空间,一个线程挂了,可能影响到其他的线程池,甚至导致整个进程崩溃
谢谢你能看到这,一起进步,一起加油ヽ( ̄ω ̄( ̄ω ̄〃)ゝ