《深入理解Linux内核》-3.1. 进程,轻量级进程,和线程

3.1. 进程,轻量级进程,和线程

术语“进程”通常有几种不同的含义。这本书里,我们坚持通常的操作系统书籍里面的定义:进程是一个正在运行的程序实例。你可以把它看做一个数据结构集合,它完整的描述了程序的执行进度。

进程就像人类:它们被出生,它们有一个或多或少有意义的生命,它们有选择地生产一个或多个子进程,最终它们会死去。一个小小的不同是它们没有性别之分,一个进程只有一个父亲(没有母亲)。

从内核的角度看,进程的作用是充当一个系统资源(cpu时间,内存等)被分配的实体。

进程被创建时几乎和父进程一模一样。它接收一个父进程地址空间的(逻辑)拷贝,执行和父进程一样的代码,从进程创建系统调用后的下一个指令开始。虽然父子进程可能共享相同的程序代码页(text),但它们有着不同的数据拷贝(栈和堆),因此子进程对内存的修改对父进程是不可见的,反之亦然。

虽然早期的unix内核采用这个简单的模型,现代的unix系统不这么做。它们支持多线程应用,用户程序拥有很多相对独立的执行流,这些执行流共享大多的应用程序数据结构。在这样的系统里,一个进程由若干用户线程(或简单线程)组成,每个代表一个进程的执行流。如今,大部分的多线程应用都是用一个叫做pthread库提供的一套标准库函数来写的。

旧版本的linux内核不提供多线程支持。从内核角度看,一个多线程应用仅仅是一个普通的进程,它的多个执行流完全是在用户态创建、处理、和调度的,通常是使用一个符合posix标准的pthread库来实现。

然而,这样的多线程应用的实现并不总是能满足需求的。举个例子,设想一个象棋程序使用两个线程:一个控制图形棋盘,等待人类玩家的操作并显示计算机的动作,而另一个线程思考下一步怎么走。当第一个线程等待人类玩家的动作时,第二个线程应该继续运行,以此来充分利用人类玩家的思考时间。但是,如果那个象棋程序仅仅是单进程的,第一个线程不能简单的发起一个阻塞调用来等待用户操作,否则第二个进程也被同时阻塞了。相反,第一个线程必须使用成熟的非阻塞技术来保证进程的继续运行。

Linux使用轻量级进程来提供对多线程更好的支持。基本地,两个轻量级进程可能共享相同的资源,像地址空间、打开的文件等。每当其中一个修改共享资源时,另一个能立刻看到这个改变。当然,这两个进程必须在访问共享资源时相互同步。

一个简单粗暴的实现多线程应用的方式是使轻量级进程和每个线程相关联。这种方式下,通过共享相同的内存地址空间、相同的打开文件集等,多个线程可以访问一组相同的应用程序数据结构;同时,每个线程又可以被内核独立调度,因此一个睡眠时,另一个还能继续运行。符合posix标准的使用轻量级进程的pthread线程库有:LinuxThreads, Native POSIX Thread Library(NPTL),和IBM的Next Generation Posix Threading Package(NGPT)。

处理posix标准的多线程应用程序最好的是支持“线程组”的内核。在linux里,线程组基本上是一组轻量级进程,它们实现了多线程应用程序,并且对于某些系统调用却是作为一个整体的,比如getpid(),kill(),和_exit()。接下来,我们将在本章详尽的介绍它们。

猜你喜欢

转载自blog.csdn.net/ybxuwei/article/details/78531372