区别和联系
我们经常提到线程、线程组、内核进程、用户进程、轻量级进程等词汇,那么他们之间有什么区别和联系呢?
首先,我们需要明确一点,Linux 下并没有真正意义上的线程,甚至可以说没有进程这个概念,Linux 下只有 task,其对应的数据结构为 task_struct,这里为了方便说明以及按照比较主流的说法,我们将 task 称之为进程。
对于一个进程来说,它一定是运行在内存的某个连续或不连续的区域。
用户进程和内核进程
对于 Linux 来说,有两个概念叫做内核空间和用户空间,以 32 位 x86 架构的 Linux 为例,Linux 的虚拟地址空间为 4GB,其中前 1GB 称为内核空间,后 3GB 称为用户空间,进程运行在内核空间时称为内核态,运行在用户空间称之为用户态。对于用户态进程来说,出于程序设计方便和内存安全的角度等原因,为每个用户态进程引入了独立的虚拟地址空间,其被映射到用户空间。
用户进程,平时运行在用户态,有自己的虚拟地址空间,但是可以通过中断、系统调用等内陷到内核态。
内核进程,没有独立的地址空间,所有内核线程的地址空间都是一样的,没有自己的地址空间,所以它们的 current->mm
都为空,其运行在内核空间,本身就是内核的一部分或者说是内核的分身。
线程、轻量级进程、线程组和用户进程
我们开始说到,Linux 下没有真正意义上的线程,那么 Linux 下的线程指的是什么呢?
我们说过Linux 下只有 task,对应的数据结构为 task_struct,task_strcut 中就包含了 task 所拥有的各种资源,如果一个运行在用户空间的 task 独占 task_struct 的所有资源,我们说它是一个用户进程,当若干个 task 要共享资源时,我们把这些 task 称之为 LWP(轻量级进程)。我们通常说的 Linux 下的线程,指的也就是这些 LWP。
总结一下,Linux 的线程只是共享了资源的进程,也就是 LWP,而那些共享了资源的 task 组合在一起,我们称之为线程组。
即对于普通的用户进程,我们可以认为是只有一个 LWP 的线程组,但对于一个有着多线程的进程(线程组),其中的每一个线程都是 LWP,组内共享资源。在一个普通进程内创建线程时,就是在线程组内增加 LWP。
进程的创建
在 Linux 下,有着这几个创建进程(task)的函数:
fork
vfork
clone
pthread_create
kernel_thread
所有的这些函数,最终都是在调用do_fork()
,只是传入的参数不同
- fork(sys_fork)在调用 do_fork() 时,clone_flags 没有置位任何 clone 标志位,即创建的进程不共享任何数据。
- vfork(sys_vfork)在调用 do_fork() 时,置为了 CLONE_VFORK CLONE_VM,即共享 VM,以及当 mm_release 时子进程唤醒父进程
- clone(sys_clone)本身只进行 clone_flags 的传递
- pthread_create 则将 CLONE_VM CLONE_FS CLONE_FILES CLONE_SIGHAND 等标志位置位,即共享 VM,共享 fs info,共享打开的文件,共享信号句柄和阻塞的信号? 即除了栈是独立的,其他都是共享的,所以在 Linux 中,线程仅仅是一个使用共享资源的轻量级进程
- kernel_thread 在传递的参数基础上增加了 CLONE_VM 和 CLONE_UNTRACED。
- kernel_thread 只能由内核进程调用,创建的进程没有独立虚拟地址空间,只能运行在内核空间,为内核进程。
- fork,创建的进程与父进程不共享资源,而是写时复制,故而创建的是用户进程
- vfork,带有 CLONE_VM 标志位,故而创建的是 LWP
- pthread_create,共享各类资源,创建的也是 LWP
关于fork
vfork
clone
pthread_create
kernel_thread
以及 do_fork
更进一步的细节,先挖个坑,以后再填
搬运后记:并没有填