进程
- 进程是对运行时程序的封装,是系统进行资源调度和分配的基本单位,实现了操作系统的并发
线程
- 线程是进程的子任务,是CPU调度和分派的基本单位,用于保证程序的实时性,实现进程内部的并发
- 线程是操作系统可识别的最小执行和调度单位
- 每个线程都独自占用一个虚拟处理器,独自的寄存器组,指令计数器和处理器状态
创建成本
- 创建进程需要为进程划分出一块完整的内存空间,有大量的初始化操作,比如要把内存分段(堆栈、正文区等)
- 创建线程则简单得多,只需要确定 programer counter指针和寄存器的值,并且给线程分配一个栈用于执行程序,同一个线程间可以复用堆栈。
上下文切换
进程
当一个进程在执行时,CPU的所有寄存器的值、进程的状态及堆栈中的内容被称为该进程的上下文。当内核需要切换到另一个进程时,它需要保存当前进程的所有状态,即保存当前进程的上下文,以便在再次执行该进程时,能够得到切换时的状态执行下去。在linux中,当前进程上下文均被保存在进程的任务数据结构中。在发生中断时,内核就在被中断进程的上下文中,在内核态下执行中断服务例程。但同时会保留所有需要用到的资源,以便中断服务结束时能恢复被中断进程的执行。
线程
线程是调度的基本单位,进程是资源拥有的基本单位。内核中的任务调度,实际上调度的对象是线程,进程是给线程提供虚拟内存、全局变量等资源的。当进程拥有多个线程时,线程共享相同的虚拟内存和全局变量等资源,这些资源在上下文切换时不需要修改。当线程也有自己的私有数据时,比如自己的栈和寄存器,上下文切换时也需要保存。
线程的上下文切换存在两种情况:
- 前后切换的两个线程属于同一个进程,两个线程的资源基本是共享的,切换上下文时共享的资源不需要动,只有当线程有私有数据时,切换这些不共享的数据即可。
- 前后切换的两个线程不属于同一个进程,跟切换进程的上下文是一样的。
切换同一进程的线程比切换进程消耗更少的系统资源,是多线程对比对进程的优势
同一个进程的线程中的资源分配
线程之前独有的资源
thread context
- 函数运行时需要额外的寄存器来保存一些信息,像局部变量,这些寄存器是线程私有的,一个线程不可能访问到另一个线程的这类寄存器信息。
- 所属线程的栈区、程序计数器、栈指针以及函数运行使用的寄存器是线程私有的,这些信息有一个统一的名字,线程上下文,thread context
TLS -- Thread Local Storage
存放在该区域中的变量的是全局变量,所有线程都可以访问,但是每个线程在访问的时候都会存储一份成为自己的局部变量,修改就不会相互影响了。看上去所有的线程访问的都是同一个变量,但该全局变量独属于一个线程,一个线程对此变量的修改对其他线程不可见。
实现原理类似有一个全局的词典,词典的key是线程id,value就是共享的全局变量的副本。
线程之前共享的资源
代码区
编译后的代码
数据区
全局变量,静态变量
堆区
C/C++中用malloc或者new 出来的数据就存放在这个区域,只要知道指针,任何一个线程都可以访问指针指向的数据,因此堆区也是线程共享的属于进程的资源。
栈区
如果一个线程能拿到来自另一个线程栈上的指针,那么该线程就可以改变另一个线程的栈区,也就是说这些线程可以任意修改本属于另一个线程栈区中的变量。
动态链接库
动态链接的部分生成的库就是我们熟悉的动态链接库,在windows下是以ddl结尾的文件,在linux下是以so结尾的文件。
文件
如果程序在运行过程中打开了一些文件,那么进程地址空间中还保存有打开的文件信息,进程打开的文件也可以被所有的线程使用,这也属于线程间的共享资源
网友评论