目录
- 一、认识操作系统
- 二、认识进程
- 三、内存管理
- 四、什么是线程(Thread)?
- 五、为什么要有线程?
- 六、进程和线程的关系
一、认识操作系统
我们需要简单了解一下操作系统。
操作系统是一组主管并控制计算机操作、运用和运行硬件、软件资源和提供公共服务来组织用户交互的相互关联的系统软件程序。根据运行的环境,操作系统可以分为桌面操作系统,手机操作系统,服务器操作系统,嵌入式操作系统等。
操作系统相当于是一个“搞管理”的软件
1.管理硬件设备
2.管理软件资源
所谓的管理:两个方面:描述+组织
操作系统主要包括以下几个方面的功能 :
①进程管理,其工作主要是进程调度,在单用户单任务的情况下,处理器仅为一个用户的一个任务所独占, 进程管理的工作十分简单。但在多道程序或多用户的情况 下,组织多个作业或任务时,就要解决处理器的调度、 分配和回收等问题 。
②存储管理分为几种功能:存储分配、存储共享、存储保护 、存储扩张。
③设备管理分有以下功能:设备分配、设备传输控制 、设备独立性。
④文件管理:文件存储空间的管理、目录管理 、文件操作管理、文件保护。
⑤作业管理是负责处理用户提交的任何要求。
应用程序:类似QQ之类的
系统调用:操作系统给应用程序提供API,比如有个程序想操作一下硬件设备,就需要先通过系统调用,把操作命令告诉给系统内核,内核调用驱动程序,进一步的操作硬件设备。
操作系统内核:是操作系统的核心功能, (对上,对下)
驱动程序:: 硬件厂商在开发硬件的同时会提供驱动程序, 电脑安装了对应的驱动程序, 才能让系统正确的识别硬件设备.
硬件设备:打开你电脑的后盖壳,看到的就是硬件设备
常见的操作系统:
Windows:windows98, 2000, xp, vista,win7, win10, win11(最熟悉的操作系统).
Linux: 特别适合进行开发和部署(程序员必须掌握的系统).
Mac: 苹果电脑用的系统, 和Linux有一些相似之处.
还有一些手机上运行系统;Android ,IOS等.
二、认识进程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。
说白了,一个跑起来的程序就是一个进程,没跑起来的就不是!
关于进程,最核心的问题,就是进程在系统中是如何被管理的?
管理 = 描述(PCB) + 组织
PCB:进程控制块,这是一个类/C语言的结构体,一个结构体对象就对应一个进程
组织:使用一定的数据结构来组织(一种常见的做法就是使用双链表)
查看进程列表,本质上就是遍历操作系统内核中的这个链表并显示其中的属性
创建一个进程,本质上就是创建一个PCB对象,加入到内核的链表中
销毁一个进程,本质上就是把这个PCB对象从内核链表中删除掉
PCB中大概有哪些属性?
pid:一个进程的的身份标识,一个机器同一时刻,不可能有两个进程的pid相同
内存指针:描述了这个进程使用的内存空间是哪个范围…
文件描述符:描述了这个进程都打开了哪些文件(系统中打开了一个文件,其实就得到了一个"文件描述符")
这个文件描述符就像一个"遥控器一样",文件数据是在磁盘上的.代码中操作磁盘数据不像操作内存数据那么方便,所以往往是借助这种"遥控器"的方式才操作…文件描述符(其实就是一个整数)
进程调度的相关属性
1.进程的状态
指的是当前的这个进程是:
就绪状态(随时能够去CPU执行)
睡眠状态(进程要等待用户的输入,就好比qq对话框,你要输入内容,但系统不知道你要什么时候输入,所以系统就让这个进程去等待,等待用户输入之后才能继续往下执行)
结束状态:(进程被关闭)
2.优先级
相当于安排发面包,谁先给发面包,谁后给发面包。
提一下并行和并发的概念:
并行:同一时刻上,两个核心上的进程,就是同时执行的。
多个CPU,运行多个进程
如:CPU1运行进程1,CPU2运行进程2
进程1和进程2无论是微观还是宏观,都是同时执行的
真实的计算机,真实的操作系统在进行进程调度的时候,是并发并行两种策略综合使用的
并发:同一时刻,一个核心上只能运行一个进程.
运行第一个进程运行一会再运行第二个,第二个运行一会再运行第三个,以此运行.由于CPU的运行速度极快,虽然CPU一直进行切换,但是咱们坐在电脑前的用户,是感知不到这个切换的过程的~~
3.上下文
进程的上下文,主要是存储调度出CPU之前,寄存器中的信息(把寄存器信息保存到内存中)
进程本身是感知不到自己是啥时候被调度出CPU的,就是CPU中的各个寄存器的值, 所以进程调出CPU之前, 需要先把CPU上寄存器上的数据保存到内存中,相当于存档; 下次该进程再被调进CPU时, 就可以根据上次储存在内存中的数据恢复到寄存器中, 相当于读档.
4.记账信息
操作系统统计每个进程在CPU上的占用的时间以及指令数目, 根据这个来决定下一阶段如何调度.
操作系统何时进行进程调度(啥时候把进程放到CPU上,啥时候把进程切换出CPU)这个事情对于进程本身来说,是感知不到的(抢占式执行)
执行到进程中的任意指令,都可能随时产生这样的调度.此时,这样的调度其实给我们的代码引入了一定的随机性,对于我们代码的正确性来说,就产生了新的挑战
三、内存管理
其实我们所说的内存不是硬件上真实存在的地址,而是虚拟内存,也就是虚拟地址空间。
内存可以理解为内存条,上面可以存放很多的数据。
下面这个就是内存条。
为啥要搞一个“虚拟地址空间”?为啥不让进程直接访问真实的物理地址?
目的是为了一定程度的减少内存访问越界,带来的后果。
例如现在有两个进程:进程1和进程2,如下
进程1的内存访问范围是0x100 ~ 0x800,如果我们的代码尝试访问0x801的地址,就是越界访问,如果这是以恶搞真实的物理内存,这个修改就真的把0x801改了,如果这个801正好是进程2要用的内存,此事进程2可能就出bug了,如果进程访问的是虚拟进程,也尝试修改0x801,此时系统就要针对0x801来查询页表,找到对应的物理地址,由于0x801已经是非法地址,再页表中查不到,系统就知道你再越界访问,于是就直接让这个进程崩溃,分支影响到其他的进程。
四、什么是线程(Thread)?
一个线程就是一个 “执行流”. 每个线程之间都可以按照顺讯执行自己的代码. 多个线程之间 “同时” 执行着多份代码. 线程是进程内部的一部分, 将进程类比作一个工厂, 那么线程就是工厂中的生产线, 所以一个进程可以包括很多个线程, 一个进程至少拥有一个线程.
五、为什么要有线程?
“并发编程”成为“刚需”
- 单核 CPU 的发展遇到了瓶颈. 要想提高算力, 就需要多核 CPU. 而并发编程能更充分利用多核 CPU 资源.
- 有些任务场景需要 "等待 IO", 为了让等待 IO 的时间能够去做一些其他的工作, 也需要用到并发编 程.
虽然多线程也能实现并发编程,但是线程比进程更轻量
- 创建线程比创建进程更快.
- 销毁线程比销毁进程更快.
- 调度线程比调度进程更快.
线程虽然比进程轻量, 但是人们还不满足, 于是又有了 “线程池”(ThreadPool) 和 “协程”
六、进程和线程的关系
进程包含线程, 一个进程包含一个或者多个线程.
进程间是独立的, 每个进程都有独立的地址空间, 一个进程崩溃不会影响其余的进程, 但是在同一个进程中, 多个线程是共用的是一块资源, 一个线程崩溃, 这个进程中的所有线程都会崩溃.
进程是操作系统分配资源的基本单位, 线程是操作系统调度执行的基本单位.
多进程相比于多线程不会存在线程安全的问题, 多线程编程可能存在线程安全问题.