一、共同点
内核
在内核的视角,进程与线程都被视为task
,每一个进程或线程对应一个task_struct
struct task_struct {
...
pid_t pid; // 进程ID(线程ID)
pid_t tgid; // 线程组ID
struct mm_struct *mm; // 进程的内存描述符
struct mm_struct *active_mm;
struct files_struct *files; // 打开的文件列表
struct signal_struct *signal; // 信号描述符
...
};
pid
:Linux中线程与进程都有唯一的PIDtgid
:线程组ID,由同一个进程所创建线程的tgid相同,等于创建它们的进程IDmm
:指向mm_struct
的指针,描述进程的虚拟地址空间,多线程共享一个mm,而不同进程拥有独立的mmfiles
: 文件描述符表,所有线程共享同一组打开的文件描述符
进程调度
在Linux中,进程和线程是统一调度的,调度器只负责调度task_struct
实例,不论进程或线程
二、不同点
内核
由于两者都由task_struct
表示,区别主要体现在 task_struct
中某些字段的共享与否上,而这些字段是否共享,是由clone()
创建新任务时,参数flag来决定新任务(进程或线程)是否与父任务共享某些关键资源
进程:
- 独立的
task_struct
,每个进程都有自己的pid
和tgid
。 - 独立的
mm_struct
,即独立的地址空间。 - 独立的信号处理机制。
线程
- 线程有自己的栈空间和寄存器,但共享全局变量和堆
- 每个线程也有独立的
task_struct
,但它们的tgid
是相同的。 - 线程共享同一个
mm_struct
,即同一个地址空间。 - 线程共享文件描述符表和信号处理机制。
上下文切换
进程
虚拟内存与物理内存的映射需要查页表,TLB缓存记录映射关系,可以加快查询速度,而上下文切换时会切换页表(cr3
寄存器指向新的页表),TLB失效,切换到新进程后查页表速度很慢,因为缓存命中率低。切换页表是进程切换的主要开销
线程
由于同一进程内的线程共享虚拟内存地址空间,没有切换页表(即切换cr3寄存器),也不会刷新TLB,内核只需保存当前线程的寄存器状态、程序计数器、堆栈指针等,开销相对较小
推荐学习 https://xxetb.xetslk.com/s/p5Ibb