简洁版:https://blog.csdn.net/qq_59084325/article/details/126534868?spm=1001.2014.3001.5502
Linux内核并不区分进程和线程,对于内核而言,进程与线程无非是共享资源的区别,对CPU调度来说并没有显著差异。

定义:进程是处于执行状态的代码以及相关资源的集合,不仅仅是代码段(text section),还包括文件,信号,CPU状态,内存地址空间、线程等。

是:正在执行的程序代码的实时结果。

两种虚拟机制

虚拟处理器:make lots task feel like owning cpu privately

虚拟内存: make task feel like onwing the whole memory

分配进程描述符(struct thread_info)

通过slab分配器来分配task_struct结构,达到对象复用和缓存着色/现在用thread_info

进程描述符的存放(PID)

内核通过一个唯一的进程标识值(process identification value)即PID了标识进程,类型为PID_t,其实是一个int类型,但默认最大值为 short int的max32768,也规定了最大进程数,可通过如下路径修改。

Tgid: 线程组的ID,一个线程一定属于一个线程组(进程组).(或线程组的主线程的PID)
Pid: 进程的ID,更准确的说应该是线程的ID
PPid: 当前进程的父进程
每个进程的资源是有上限,可通过cat /proc//limits查看
TID:thread ID,线程ID
在主线程中pid=tid,子线程中不相等
还有就是tid间资源不共享,而pid与其他线程共享资源
一个线程组有一个主线程和n个子线程(比如线程组的TGID=PID=1000--由进程fork()创建,父进程为999)
其主线程 :  PID=TGID
其子线程 :TID!=TGID

大部分处理进程的代码直接通过task struct的指针*task来直接操作。一般x86在内核栈的尾端创建thread_info,通过计算偏移间接查找task_struct.

进程状态state

设置当前进程状态:set_task_state(task,state)/set_current_state(state)

家族进程树

3.3 进程创建

写时拷贝     
传统的:把所有资源复制给新进程,简单、效率低下:拷贝的数据可能不能共享且此拷贝可能会被打断。
linux通过copy-on-write页实现,内核不复制,让父进程和子进程共享同一拷贝,只有在需要时,数据才会被复制。
fork()

vfork()

不拷贝父进程的页表项,其他与fork()一致

exec()一族函数负责读取可执行文件并载入地址空间运行

3.4 线程创建

Linux用户级线程创建:通过pthread库中的pthread_create()创建线程

Linux内核线程创建: 通过kthread_create()

3.5 进程终结

进程的析构发生在进程调用exit()系统调用。大部分靠do_exit()完成

之后:

删除进程描述符

孤儿进程则需要寻找新父进程

linux操作系统中进程和线程的区别?

相同点:

所有的线程都当作进程来实现,因为没有单独为线程定义特定的调度算法,也没有单独为线程定义特定的数据结构(所有的线程或进程的核心数据结构都是 task_struct)。

对于一个进程,相当于是它含有一个线程,就是它自身。对于多线程来说,原本的进程称为主线程,它们在一起组成一个线程组。

不同点:

进程拥有自己的地址空间,所以每个进程都有自己的页表。而线程却没有,只能和其它线程共享某一个地址空间和同一份页表。

这个区别的根本原因是,在进程/线程创建时,因是否拷贝当前进程的地址空间还是共享当前进程的地址空间,而使得指定的参数不同而导致的。

具体地说,进程和线程的创建都是执行 clone 系统调用进行的。而 clone 系统调用会执行 do_fork 内核函数,而它则又会调用 copy_process 内核函数来完成。主要包括如下操作:

1、在调用 copy_process 的过程中,会创建并拷贝当前进程的 task_stuct,同时还会创建属于子进程的 thread_info 结构以及内核栈。
2、此后,会为创建好的 task_stuct 指定一个新的 pid(在 task_struct 结构体中)。
3、然后根据传递给 clone 的参数标志,来选择拷贝还是共享打开的文件,文件系统信息,信号处理函数,进程地址空间等。这就是进程和线程不一样地方的本质所在。

linux线程(进程)和内核线程的区别?

内核线程是一种只运行在内核地址空间的线程。所有的内核线程共享内核地址空间(对于 32 位系统来说,就是 3-4GB 的虚拟地址空间),所以也共享同一份内核页表。这也是为什么叫内核线程,而不叫内核进程的原因。

普通线程虽然也是同主线程共享地址空间,但是它的 task_struct 对象中的 mm 不为空,指向的是主线程的 mm_struct 对象。

内核线程只运行在内核态,而普通进程既可以运行在内核态,也可以运行在用户态。

内核线程只使用 3-4GB (假设为 32 位系统) 的内核地址空间(共享的),但普通进程由于既可以运行在用户态,又可以运行在内核态,因此可以使用 4GB 的虚拟地址空间。

Linux内核空间和用户空间的区别?

用户空间到内核空间的切换方式:系统调用、异常、中断。