当前位置:Linux教程 - Linux综合 - Linux 核心

Linux 核心

  进程及进程间通讯机制 程序是保存在磁盘上的文件,其中包含了计算机的执行指令和数据,而进程则可以看成是运行中的程序。程序是静态的,而进程是动态的。和进程联系在一起的不仅有进程的指令和数据,而且还有当前的指令指针、所有的 CPU 寄存器以及用来保存临时数据的堆栈等,所有这些都随着程序指令的执行在变化。 进程在运行过程中,要使用许多计算机资源,例如 CPU、内存、文件等。Linux 是一个多任务操作系统,同时可能会有多个进程使用同一个资源,因此操作系统要跟踪所有的进程及其所使用的系统资源,以便能够管理进程和资源。 Linux 是一个多任务操作系统,它要保证 CPU 时刻保持在使用状态,如果某个正在运行的进程等待外部设备完成工作(例如等待打印机完成打印任务),这时,操作系统就可以选择其他进程运行,从而保持 CPU 的最大利用率。这就是多任务的基本思想,进程之间的切换由调度程序完成。 Linux 中的每个进程有自己的虚拟地址空间,操作系统的一个最重要的基本管理目的,就是避免进程之间的互相影响。但有时用户也希望能够利用两个或多个进程的功能完成同一任务,为此,Linux 提供许多机制,利用这些机制,进程之间可以进行通讯并共同完成某项任务,这种机制称为“进程间通讯(IPC)”。信号和管道是常见的两种 IPC 机制,但 Linux 也提供其他 IPC 机制。 本章主要描述 Linux 进程的管理、调度以及 Linux 系统支持的进程间通讯机制。 11.1 Linux 进程及线程 Linux 内核利用一个数据结构(task_strUCt)代表一个进程,代表进程的数据结构指针形成了一个 task 数组(Linux 中,任务和进程是两个相同的术语),这种指针数组有时也成为指针向量。这个数组的大小默认为 512,表明在 Linux 系统中能够同时运行的进程最多可有 512。当建立新进程的时候,Linux 为新的进程分配一个 task_struct 结构,然后将指针保存在 task 数组中。task_struct 结构中包含了许多字段,按照字段功能,可分成如下几类: 标识号。系统通过进程标识号唯一识别一个进程,但进程标识号并不是进程对应的 task_struct 结构指针在 task 数组中的索引号。另外,一个进程还有自己的用户和组标识号,系统通过这两个标识号判断进程对文件或设备的访问权。 状态信息。一个 Linux 进程可有如下几种状态:运行、等待、停止和僵死。 调度信息。调度程序利用该信息完成进程之间的切换。 有关进程间通讯的信息。系统利用这一信息实现进程间的通讯。 进程链信息。在 Linux 系统中,除初始化进程之外,任何一个进程都具有父进程。每个进程都是从父进程中“克隆”出来的。进程链则包含进程的父进程指针、和该进程具有相同父进程的兄弟进程指针以及进程的子进程指针。另外,Linux 利用一个双向链表记录系统中所有的进程,这个双向链表的根就是 init 进程。利用这个链表中的信息,内核可以很容易地找到某个进程。 时间和定时器。系统在这些字段中保存进程的建立时间,以及在其生命周期中所花费的 CPU 时间,这两个时间均以 jiffies 为单位。这一时间由两部分组成,一是进程在用户模式下花费的时间,二是进程在系统模式下花的时间。Linux 也支持和进程相关的定时器,应用程序可通过系统调用建立定时器,当定时器到期时,操作系统会向该进程发送 SIGALRM 信号。 文件系统信息。进程可以打开文件系统中的文件,系统需要对这些文件进行跟踪。系统使用这类字段记录进程所打开的文件描述符信息。另外,还包含指向两个 VFS 索引节点的指针,这两个索引节点分别是进程的主目录以及进程的当前目录。索引节点中有一个引用计数器,当有新的进程指向某个索引节点时,该索引节点的引用计数器会增加计数。未被引用的索引节点的引用计数为 0,因此,当包含在某个目录中的文件正在运行时,就无法删除这一目录,因为这一目录的引用计数大于0。 和进程相关的上下文信息。如前所述,进程可被看成是系统状态的集合,随着进程的运行,这一集合发生变化。进程上下文就是用来保存系统状态的 task_struct 字段。当调度程序将某个进程从运行状态切换到暂停状态时,会在上下文中保存当前的进程运行环境,包括 CPU 寄存器的值以及堆栈信息;当调度程序再次选择该进程运行时,则会从进程上下文信息中恢复进程的运行环境。 11.1.1 标识符信息 和所有的 UNIX 系统一样,Linux 使用用户标识符和组标识符判断用户对文件和目录的访问许可。Linux 系统中的所有文件或目录均具有所有者和许可属性,Linux 据此判断某个用户对文件的访问权限。对一个进程而言,系统在 task_struct 结构中记录如表 11-1 所示的四对标识符。 表 11-1 进程的标识符信息 uid 和 gid 运行进程所代表的用户之用户标识号和组标识号,通常就是执行该进程的用户。   有效uid 和 gid 某些程序可以将 uid 和 gid 改变为自己私有的 uid 和 gid。系统在运行这样的程序时,会根据修改后的 uid 及 gid 判断程序的特权,例如,是否能够直接进行 I/O 输出等。通过 setuid 系统调用,可将程序的有效 uid 和 gid 设置为其他用户。在该程序映象文件的 VFS 索引节点中,有效 uid 和 gid 由索引节点的属性描述。
[1] [2] 下一页 

  文件系统uid 和 gid 这两个标识符和上述标识符类似,但用于检查对文件系统的访问许可时。处于用户模式的 NFS 服务器作为特殊进程访问文件时使用这两个标识符。   保存uid 和 gid 如果进程通过系统调用修改了进程的 uid 和 gid,这两个标识符则保存实际的 uid 和 gid。   11.1.2 进程状态信息 如前所述,Linux 中的进程有四中状态,如表 11-2 所示。 表 11-2 进程的状态信息 运行状态 该进程是当前正在运行的进程;或者,该进程是可以运行的进程,即正在等待调度程序将 CPU 分配给它。   等待状态 进程正在等待某个事件或某个资源。这种进程又分为可中断的进程和不可中断的进程两种。可中断的等待进程可被信号中断,而不可中断的等待进程是正在直接等待硬件状态条件的进程,在任何情况下都不能被中断。   停止状态 进程处于停止状态,通常由于接收到信号而停止,例如,进程在接收到调试信号时处于停止状态。   僵死状态 进程已终止,但在 task 数组中仍占据着一个 task_struct 结构。顾名思义,处于这种状态的进程实际是死进程。   11.1.3 文件信息 如图 11-1 所示,系统中的每个进程有两个数据结构用于描述进程与文件相关的信息。其中,fs_struct 描述了上面提到的两个 VFS 索引节点的指针,即 root 和 pwd。另外,这个结构还包含一个 umask 字段,它是进程创建文件时使用的默认模式,可通过系统调用修改这一默认模式。另一个结构为files_struct,它描述了当前进程所使用的所有文件信息。从图中可以看出,每个进程能够同时拥有 256 个打开的文件,fs[0] 到 fs[255] 就是指向这些 file 结构的指针。文件的描述符实际就是 fs 指针数组的索引号。 在 file 结构中,f_mode 是文件的打开模式,只读、只写或读写;f_pos 是文件的当前位置;f_inode 指向 VFS 中该文件的索引节点;f_op 包含了对该文件的操作例程集。利用 f_op,可以针对不同的文件定义不同的操作函数,例如一个用来向文件中写数据的函数。Linux 利用这一抽象机制,实现了管道这一进程间通讯机制(将在后面详细描述)。这种抽象方法在 Linux 内核中非常常见,通过这种方法,可使特定的内核对象具有类似 C++ 对象的多态性。 Linux 进程启动时,有三个文件描述符被打开,它们是标准输入、标准输出和错误输出,分别对应 fs 数组的三个索引,即 0、1和2。如果启动时进行输入输出重定向,则这些文件描述符指向指定的文件而不是标准的终端输入/输出。每当进程打开一个文件时,就会利用files_struct 的一个空闲 file 指针指向打开的文件描述结构 file。对文件的访问通过 file 结构中定义的文件操作例程和 VFS 索引节点信息来完成。 11.1.4 虚拟内存 在前一章中看到,进程的虚拟内存包含了进程所有的可执行代码和数据。运行某个程序时,系统要根据可执行映象中的信息,为进程代码和数据分配虚拟内存;进程在运行过程中,可能会通过系统调用动态申请虚拟内存或释放已分配的内存,新分配的虚拟内存必须和进程已有的虚拟地址链接起来才能使用;Linux 进程可以使用共享的程序库代码或数据,这样,共享库的代码和数据也需要链接到进程已有的虚拟地址中。在前一章中还看到,系统利用了需求分页机制来避免对物理内存的过分使用。因为进程可能会访问当前不在物理内存中的虚拟内存,这时,操作系统通过对处理器的页故障处理装入内存页。为此,系统需要修改进程的页表,以便标志虚拟页是否在物理内存中,同时,Linux 还需要知道进程地址空间中任何一个虚拟地址区域的来源和当前所在位置,以便能够装入物理内存。   图 11-1 进程的文件信息 由于上面这些原因,Linux 采用了比较复杂的数据结构跟踪进程的虚拟地址。

(出处:http://www.sheup.com)


上一页 [1] [2] 

  图 11-1 进程的文件信息 由于上面这些原因,Linux 采用了比较复杂的数据结构跟踪进程的虚拟地址。

(出处:http://www.sheup.com)


上一页 [1] [2] [3]