进程
- 它是处于执行期的程序,或者说“进程=程序+执行”。但是进程并不仅局限于一段可执行代码(代码段),它还包括进程所需要的其他资源,例如打开的文件、挂起的信号量、内存管理、处理器状态、一个或者多个执行线程和数据段等。Linux内核通常把进程叫做是任务(task),因此进程控制块(processing contrl block, PCB)也被命名为struct task_struct。——《奔跑吧Linux内核 3.1章》
线程
- 线程机制是现代编程技术种常用的一种抽象概念。——《Linux内核设计与实现》
- 线程最主要的目的就是更好的支持SMP以及减小(进程/线程)上下文切换开销。
- 针对线程模型的两大意义,分别开发出了核心级线程和用户级线程两种线程模型,分类的标准主要是线程的调度者在核内还是在核外。前者更利于并发使用多处理器的资源,而后者则更多考虑的是上下文切换开销。在目前的商用系统中,通常都将两者结合起来使用,既提供核心线程以满足smp系统的需要,也支持用线程库的方式在用户态实现另一套线程机制,此时一个核心线程同时成为多个用户态线程的调度者。正如很多技术一样,"混合"通常都能带来更高的效率,但同时也带来更大的实现难度,出于"简单"的设计思路,Linux从一开始就没有实现混合模型的计划,但它在实现上采用了另一种思路的"混合"。
- 从Linux内核的角度看,线程和进程是一样的,同样的数据结构,同样的调度算法。线程只是一种和其它进程共享某些资源的进程。线程机制是现代编程技术种常用的一种抽象概念。——《Linux内核设计与实现》
- Windows和Solaris等系统,在内核中提供了专门支持线程的机制。假如我们有一个包含4个线程的j进程,在专门提供线程支持的系统中,通常会一个包含四个不同线程的指针的进程描述符。该描述符负责描述像地址空间、打开的文件这样的共享资源,线程本身再去描述它独占的资源。相反,Linux仅仅创建四个进程并分配四个普通的tash_struct结构。建立这四个进程时指定他们的共享资源。——《Linux内核设计与实现》
- 线程被称为轻量级进程,它是操作系统调度的最小单元,通常一个进程可以拥有多个线程。线程和进程的区别在于进程拥有独立的资源空间,而线程则共享进程的资源空间。Linux内核没有对线程有特别的调度算法或定义特别的数据结构来标识线程,线程和进程都使用相同的进程PCB数据结构。内核里使用clone方法来创建线程,进程用fork方法来创建。clone的工作方式和创建进程的fork方法类似,但会确定哪些资源和父进程共享,哪些资源为线程独享。——《奔跑吧Linux内核 3.1章》
- Linux线程的实现知名的有3个,分别是LinuxThreads,NPTL(Native Posix Thread Library),NGPT(Next Generation Posix Threading)。最早是LinuxThreads,但在信号处理、调度和进程间同步原语方面都存在问题。后来POSIX标准提了一些要求,RedHat 公司牵头研发了 NPTL(Native Posix Thread Library),IBM投资开发了 NGPT(Next Generation Posix Threading),二者都是围绕完全兼容POSIX 1003.1c。大多数Linux系统选择了NPTL,NGPT就被放弃了。Linux2.6起,基本上使用了NPTL。
- Linux的线程实现是在核外进行的,核内提供的是创建进程的接口do_fork()。内核提供了两个系统调用__clone()和fork(),最终都用不同的参数调用do_fork()核内API。当然,要想实现线程,没有核心对多进程(其实是轻量级进程)共享数据段的支持是不行的,因此,do_fork()提供了很多参数,包括CLONE_VM(共享内存空间)、CLONE_FS(共享文件系统信息)、CLONE_FILES(共享文件描述符表)、CLONE_SIGHAND(共享信号句柄表)和CLONE_PID(共享进程ID,仅对核内进程,即0号进程有效)。当使用fork系统调用时,内核调用do_fork()不使用任何共享属性,进程拥有独立的运行环境,而使用pthread_create()来创建线程时,则最终设置了所有这些属性来调用__clone(),而这些参数又全部传给核内的do_fork(),从而创建的"进程"拥有共享的运行环境,只有栈是独立的,由__clone()传入。