有一句概念“进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位。”
分上下句去理解他吧,首先贴一张图
所看到是一个进程的内存空间,分为一些栈区,堆区,一些资源区等等。
“进程是操作系统资源分配的基本单位”,进程包含一个程序的执行实例,说的具体点就是他有自己的内存空间,文件描述符等。进程和进程之间相互独立,隔离,进程之间通过(IPC)来进行数据交换和协作。再具象一点进程就是上图的一段空间。
“而线程是处理器任务调度和执行的基本单位。”,可以把线程理解成生产线,一个生产车间就是进程。一个生产车间里面至少有一个生产车线,工人根据一定的策略去选择生产线进行生产,某条生产线完成之后根据一定的策略去选择另外一条生产线。在计算机当中就表现为,一个进程当中至少有一个线程用力进行任务执行,处理单元根据一定的策略去选择要执行的线程,执行结束后选择下一条线程(这一定程度上也是并发)。线程之间有资源共享,这也意味着如果一个线程出现了问题,其他线程可能也会出现问题。
那一个进程是如何创造出来的呢?
- 分配空间 操作系统要为新的进程分配内存空间,用于存储程序的代码,数据和堆栈等信息
- 设置上下文,要为新的进程建立独立的执行环境,比如PC,寄存器等等
- 加载程序 操作系统将可执行程序或者运行时文件
- 初始化资源 需要初始化进程需要访问的各种资源(文件,网络连接,设备)等
- 启动执行 在上面这些步骤完成之后,操作系统会将进程的执行引导到程序的入口点,开始执行相应的代码。
。
。
一个线程是如何创造出来的呢?
需要注意的是线程是进程被创造出来之后创造的。 - 线程创建函数调用 编写程序的时候CreateThread这类函数创造一个新的线程,这些函数通常接受一个线程入口函数,和函数作为参数。
- 创建线程控制块,也就是昨天的TCB。操作系统会在内核区域开辟一块新的内存区域,保存该线程的信息,这个内存的区域就是用来存放TCB的。
- 初始化线程属性 初始化一些属性,例如这个优先级,调度的策略等等。
- 分配线程栈空间 就是我之前所理解的分配在进程空间当中的栈区。
- 设置线程入口函数和参数 将上面创建线程时候的参数和函数作为参数,将这些信息保存在TCB当中。
- 线程调度和执行 创建之后就进入了就绪状态,等着调度算法调度他进入运行态。
。
。
关于线程的栈区与栈帧
上面已经了解到,被创建的线程都有一个他专属的栈区,那栈帧是什么东西?
栈帧是一种数据结构,用来活动记录,每次函数调用都会创建一个栈帧,存储该函数的参数啊,返回地址啊局部变量啊等等函数调用。
需要注意的是栈帧被存放在线程的栈区内,每调用一个新的线程的新的函数,就会创建出一个新的栈帧,待到这个任务结束后需要调用新的线程的新的函数,就会将旧的线程的上下文保存在他的栈帧里面,然后创建出一个新的线程的栈帧。等到这个新的线程被执行结束之后需要调用回去,就不用创建出新的栈帧,而是恢复之前那个保存的栈帧。
所以也可以将栈区的大小一定程度上由最多产生的栈帧数目来决定。
。
。
而如何判断一个线程可能会产生多少栈帧。
这和我们上面讲的函数由比较深的关联
函数调用深度 函数嵌套越多可能产生更多的栈帧
递归调用 如果存在递归调用的情况,那么可能每一次递归都要产生新的栈帧
函数内部的局部变量和对象 如果有大量局部变量和对象,会导致栈帧大小的增加,从而影响栈帧的数量
编译器和编译选项 数量也很大程度上取决于编译器的优化策略。