4

(1)
最大的区别

  • 进程时系统资源分配的最小单位
  • 线程时cpu操作和调度的最小单位,本质是一组寄存器的状态,是操作系统对寄存器状态的抽象

(2)
从创建和切换以及通信成本来说:

线程的创建成本远远低于进程

  • 创建进程需要为进程划分出一块完整的内存空间,有大量的初始化操作,比如要把内存分段(堆栈、正文区等)。
  • 创建线程则简单得多,只需要确定 PC 指针寄存器的值,并且给线程分配一个用于执行程序,同一个进程的多个线程间可以复用堆栈
  • 因此,创建进程比创建线程慢,而且进程的内存开销更大。

进程上下文切换

当一个进程在执行时,CPU的所有寄存器中的值、进程的状态以及堆栈中的内容被称为该进程的上下文。当内核需要切换到另一个进程时,它需要保存当前进程的所有状态,即保存当前进程的上下文,以便在再次执行该进程时,能够必得到切换时的状态执行下去。在LINUX中,当前进程上下文均保存在进程的任务数据结构中。在发生中断时,内核就在被中断进程的上下文中,在内核态下执行中断服务例程。但同时会保留所有需要用到的资源,以便中断服务结束时能恢复被中断进程的执行。

线程的上下文切换

线程和进程的区别,线程是调度的基本单位,进程时资源拥有的基本单位,怎么理解呢?所谓内核中的任务调度,实际上调度的对象是线程,而进程时给线程提供虚拟内存、全局变量等资源的。
你也可以这样理解:
当进程只有一个线程时,可以认为进程就等于线程;
当进程拥有多个线程时,这些线程共享相同的虚拟内存和全局变量等资源,这些资源在上下文切换时并不需要修改。
当线程也有自己的私有数据时,比如自己的栈和寄存器,上下文切换时也需要保存。

根据上面描述的,线程的上下文切换就存在两种情况:

  1. 前后切换的两个线程是属于同一个进程,两个线程的资源基本是共享的,切换上下文时共享的资源不需要动,只有当线程有私有数据时,切换这些不共享的数据即可;
  2. 前后切换的两个进程不属于同一个进程,跟切换进程的上下文时一样的。

切换同一进程的线程比切换进程消耗更少的系统资源,这就是多线程对比多进程的优势。

进程中的线程共享地址空间,进程间的通信的代价远大于线程间的通信

  • 管道,FIFO,消息队列,信号量,共享内存,信号,socket,UNIX套接字

线程间的通信目的主要是用于线程同步,所以线程没有像进程通信中的用于数据交换的通信机制。

  • 互斥锁,读写锁,自旋锁,信号量,条件变量和屏障

(3)
在同一个进程中的线程有共享的和独有的资源
https://cloud.tencent.com/dev...

线程之间独有的资源有

栈区

  • 同时函数运行时需要额外的寄存器来保存一些信息,像部分局部变量之类,这些寄存器也是线程私有的,一个线程不可能访问到另一个线程的这类寄存器信息。
  • 所属线程的栈区、程序计数器、栈指针以及函数运行使用的寄存器是线程私有的。这些信息有一个统一的名字,就是线程上下文,thread context。

TLS -> Thread Local Storge

  • 存放在该区域中的变量是全局变量,所有线程都可以访问他是全局的,但是每个线程在访问的时候都会存储一份成为自己的局部变量,修改就不会相互影响了
  • 虽然看上去所有线程访问的都是同一个变量,但该全局变量独属于一个线程,一个线程对此变量的修改对其他线程不可见。
  • 实现原理类似有一个全局的词典,词典的key是线程id,value就是共享的全局变量的副本。

http://blog.hacksmeta.com/201...

线程共享的资源

代码区

  • 编译后的代码

数据区

  • 全局变量,静态变量。

堆区

  • C/C++中用malloc或者new出来的数据就存放在这个区域,只要知道指针,任何一个线程都可以访问指针指向的数据,因此堆区也是线程共享的属于进程的资源。

栈区

  • 如果一个线程能拿到来自另一个线程栈帧上的指针,那么该线程就可以改变另一个线程的栈区,也就是说这些线程可以任意修改本属于另一个线程栈区中的变量。

动态链接库

  • 动态链接的部分生成的库就是我们熟悉的动态链接库,在Windows下是以DLL结尾的文件,在Linux下是以so结尾的文件。

文件

  • 如果程序在运行过程中打开了一些文件,那么进程地址空间中还保存有打开的文件信息,进程打开的文件也可以被所有的线程使用,这也属于线程间的共享资源。

仇实
23 声望0 粉丝

头像为AI合成