简洁版: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内核空间和用户空间的区别?
用户空间到内核空间的切换方式:系统调用、异常、中断。
浙公网安备 33010602011771号