工作中刚开始接触Linux,基本上编程练手就从多线程Demo开始。首先由于对于进程、线程这些基本概念进行了简单的认知。
1.程序的认识
程序:硬盘中的二进制文件
通常意义上就是我们电脑本地保存的一些文件。比如我电脑上安装好了一个QQ程序,现在它就躺在我的电脑硬盘中,我没有去启动它。这时就叫做一个程序。
2.进程的认识
进程: 加载到内存中的二进制文件 + PCB
现在我运行QQ,计算机会将程序文件从硬盘加载到系统内存中然后执行。这时QQ进程启动了,可以查看 任务管理器 中QQ这个进程就存在。
进程启动之后,所有的数据都加载到内存中。比如我们Linux编译生成一个可执行的
计算机系统启动了一个进程,那就需要去时时刻刻的管理这个进程,以便于去响应这个进程和进程结束之后的回收工作。
系统在新建一个进程的时候,会给这个进程分配 资源 和 进程控制块(PCB)。具体情况如下:
Linux系统启动一个进程,会为该进程分配一个 虚拟地址空间。
1) 对于32位系统,寻址指针为4字节,对应的虚拟地址空间为0 ~ 2^32,即 0-4G
2) 对于64位系统,寻址指针为8字节,对应的虚拟地址空间为0 ~ 2^64,即0-16G
![](https://images2018.cnblogs.com/blog/1237273/201807/1237273-20180701145346701-816854737.png)
图2.1 虚拟地址空间
2.1 虚拟地址和虚拟内存、物理内存的概念
物理内存:【跳转:参考链接1】
简单说使用角度,就是你这个计算机插的内存条是多大的,那么这就是他的物理内存。
CPU中的概念,物理内存就是CPU的地址线可以直接进行寻址的内存空间大小。
比如8086只有20根地址线,那么它的寻址空间就是1MB,我们就说8086能支持1MB的物理内存,即使我们安装了128M的内存条在板子上,我们也只能说8086拥有1MB的物理内存空间。
同理,32位的CPU就可以支持最大4GB的物理内存空间了;64位的CPU就可以支持最大16GB的物理内存空间了。所以想给电脑加内存条也不是可以随便加的。
虚拟内存:
从名字上看,“虚拟”的一块内存。实际上只是一种内存管理手段。
以上面的进程创建时的4G虚拟内存举例,并不是真的从计算机的物理内存中分配一块连续的4G内存空间给这个新建的进程使用。如果这样的话,咱们的32位计算机总共就4G大的物理内存,你要是启动个几十个进程不就把计算机的物理内存挤满了。
事实上,在每个进程创建加载时,内核只是为进程“创建”了虚拟内存的布局,实际上并不立即就把虚拟内存对应位置的程序数据和代码(比如.text .data段)拷贝到物理内存中,只是建立好虚拟内存和磁盘文件之间的映射(叫做存储器映射),等到运行到对应的程序时,才会通过缺页异常,来拷贝数据进入物理内存。
2.2 进程控制块 PCB
就像是生了孩子就得一辈子管着他、操心他一样。那么问题来了,你肯定是操心自己家的孩子,不会去操心一个陌生的孩子,因为自己孩子肯定自己认识。那么系统是通过什么来标志、识别这个运行中的进程呢?---- 就是 PCB
内核区的进程控制PCB 会携带该进程的一些信息(如:进程状态、进程标识.......),是系统感知该进程的唯一标识。Linux内核的进程控制块是 task_struct结构体。【跳转:参考文章链接1】
图1.2 PCB结构体
3. 线程的认识
线程:是cpu调度的最小单位。
一个进程启动之后,可以在这个进程中创建多个新的子线程。然后这个进程就退化成了一个线程(称:主线程)。这样该进程在运行时,就是主线程和被创建的多个子线程去轮流争取CPU的时间片,执行各自线程中的处理动作。所以我们说 线程是cpu调度的最小单位。
3.1 进程和线程的差异
(1)进程:是资源分配的基本单位。
前面提到,系统在创建一个进程时会为这个进程分配一定的资源。但是在新建线程时并没有再为这些个线程再次分配资源。所以新建的多个子线程共用该进程的地址空间。
(2)进程之间是相互独立的。而线程间是有资源依赖关系的。
例如,我们在一个父进程中,新建了多个子进程。在运行时,任何一个进程的终止,不会影响到其他进程。
在一个主线程中,新建了多个子线程。在运行时,主线程终止,创建的全部子线程被迫终止(因为主线程结束,系统回收了进程资源,这些线程没有了资源自然无法正常运行)。