文章目录
前言
在本文章中,我们将要详细介绍一下Linux中有关进程相关的内容。
一.进程
1.1 进程的概念
进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
1.2 线程的概念
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
1.3 进程地址空间
每个进程也都有自己的地址空间,这些地址都是虚拟的地址,而不是真实的物理地址。操作系统利用页表方式将进程地址空间和真实的物理地址映射起来。
栈区和堆区之间的箭头表示,随着数据的加入,栈区的地址由高地址向低地址增长
堆区的地址由低地址向高地址增长。
1.4 由虚拟地址到物理地址的页表映射(二级页表)
1.4.1 一级页表的缺点
在32位平台下有232个地址,也就是一张页表就要有232个映射关系。
每张表的内容出了映射关系外,还包含了一些权限相关信息。比如页表分为内核级页表和用户级页表,通过权限信息来区分。
每个表项中存储了一个物理地址和虚拟地址,这里一共要占用8个字节,再考虑权限相关的信息,这里粗略地认为每个表项总共占用了10个字节。
那么总共就需要232 * 10 字节,也就是40GB的大小。
在32位平台下最大的内存也就仅有4GB,说明这种页表映射的方式是不合理的。
1.4.2 二级页表
在Linux中的处理方式是建立一个二级页表。
1.虚拟地址前10个比特位在页目录中进行查找,找到相应的页表。
2.再拿10个比特位在对应页表中进行查询,找到物理内存中对应页框的起始地址。
3.将最后12个比特位作为偏移量从页框对应地址处向后偏移,找到物理内存中的某一个对应字节数据。对应页框的起始地址(20个比特位)+虚拟地址的最后12个比特位就能够定位任意一个内存字节地址。
物理地址是以“块”为单位的,这个块的大小就是4KB也就是212,对应了偏移量最大值。
这就是二级页表的结构,页目录就是一个一级页表,而表项就是一个二级页表。
接下来计算总大小。
首先只用了20个比特位来建立映射关系,那么最大也就是220个字节,也就是1MB。在页表中,左边占了10个比特位,而右边占了20个比特位,共30个比特位,这里假设加起来一共占了32个比特位(方便计算),也就是4个字节。
那么总大小就是220 * 4 byte = 4MB
映射过程是由MMU这个硬件完成的,页表是一种软件映射,MMU是一种硬件映射。
1.5 Linux中的进程
在Linux中一个进程的创建实际上伴随着进程控制块(PCB或task_struct),进程地址空间以及页表的创建。
进程控制块(Processing Control Block),是操作系统核心中一种数据结构,主要表示进程状态。其作用是使一个在多道程序环境下不能独立运行的程序(含数据),成为一个能独立运行的基本单位或与其它进程并发执行的进程。或者说,OS是根据PCB来对并发执行的进程进行控制和管理的。 PCB通常是系统内存占用区中的一个连续存区,它存放着操作系统用于描述进程情况及控制进程运行所需的全部信息,它使一个在多道程序环境下不能独立运行的程序成为一个能独立运行的基本单位或一个能与其他进程并发执行的进程。
二、线程
2.1Linux中的多线程(Linux并不存在真正意义上的线程)
Linux中每创建一个进程,都要伴随着产生进程控制块,进程地址空间,页表。
而操作系统中有大量的进程,一个进程内又可以包含多个线程,因此线程的数量一定会远远多于进程的。如果一个操作系统要真正地去支持使用线程,那么就必须有某种结构对线程进行相应的管理。比如:线程的创建,终止,转换,调度和释放回收等。
但是Linux并没有单独地为线程创建相应的结构去管理,而是复用了进程的结构。而Windows系统单独为线程创建了相应的结构去管理,会比Linux复杂很多。

2.2 线程的优点
创建一个新线程的代价要比创建一个新进程小得多
与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
线程占用的资源要比进程少很多
能充分利用多处理器的可并行数量 在等待慢速I/O操作结束的同时,程序可执行其他的计算任务
计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作。
2.3线程的缺点
性能损失
一个很少被外部事件阻塞的计算密集型线程往往无法与共它线程共享同一个处理器。如果计算密集型线程的数量比可用的处理器多,那么可能会有较大的性能损失,这里的性能损失指的是增加了额外的同步和调度开销,而可用的资源不变。
健壮性降低 编写多线程需要更全面更深入的考虑,在一个多线程程序里,因时间分配上的细微偏差或者因共享了
不该共享的变量而造成不良影响的可能性是很大的,换句话说线程之间是缺乏保护的。
缺乏访问控制
进程是访问控制的基本粒度,在一个线程中调用某些OS函数会对整个进程造成影响。
编程难度提高 编写与调试一个多线程程序比单线程程序困难得多
2.4线程异常
单个线程如果出现除零,野指针问题导致线程崩溃,进程也会随着崩溃
线程是进程的执行分支,线程出异常,就类似进程出异常,进而触发信号机制,终止进程,进程终止,该进程内的所有线程也就随即退出
2.5 线程用途
合理的使用多线程,能提高CPU密集型程序的执行效率合理的使用多线程,能提高IO密集型程序的用户体验(如生活中我们一边写代码一边下载开发工具,就是多线程运行的一种表现)
三、线程 VS 进程
线程共享进程数据,但也拥有自己的一部分数据:
线程ID; 一组寄存器; 栈; errno; 信号屏蔽字; 调度优先级
进程的多个线程共享 同一地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:
文件描述符表;每种信号的处理方式(SIG_ IGN、SIG_ DFL或者自定义的信号处理函数); 当前工作目录 ;用户id和组id\
总结
以上就是我们Linux进程与线程相关的介绍,希望对大家的学习有所帮助,仅供参考 如有错误请大佬指点我会尽快去改正 欢迎大家来评论~~