加入收藏 | 设为首页 | 会员中心 | 我要投稿 衡阳站长网 (https://www.0734zz.cn/)- 数据集成、设备管理、备份、数据加密、智能搜索!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

Linux 进程管理剖析--转

发布时间:2021-01-23 23:28:12 所属栏目:Linux 来源:网络整理
导读:地址:http://www.ibm.com/developerworks/cn/linux/l-linux-process-management/index.html Linux 是一种动态系统,能够适应不断变化的计算需求。Linux 计算需求的表现是以 进程 ?的通用抽象为中心的。进程可以是短期的(从命令行执行的一个命令),也可以
副标题[/!--empirenews.page--]

地址:http://www.ibm.com/developerworks/cn/linux/l-linux-process-management/index.html

Linux 是一种动态系统,能够适应不断变化的计算需求。Linux 计算需求的表现是以进程?的通用抽象为中心的。进程可以是短期的(从命令行执行的一个命令),也可以是长期的(一种网络服务)。因此,对进程及其调度进行一般管理就显得极为重要。

在用户空间,进程是由进程标识符(PID)表示的。从用户的角度来看,一个 PID 是一个数字值,可惟一标识一个进程。一个 PID 在进程的整个生命期间不会更改,但 PID 可以在进程销毁后被重新使用,所以对它们进行缓存并不见得总是理想的。

在用户空间,创建进程可以采用几种方式。可以执行一个程序(这会导致新进程的创建),也可以在程序内,调用一个?fork?或?exec?系统调用。fork?调用会导致创建一个子进程,而?exec?调用则会用新程序代替当前进程上下文。接下来,我将对这几种方法进行讨论以便您能很好地理解它们的工作原理。

在本文中,我将按照下面的顺序展开对进程的介绍,首先展示进程的内核表示以及它们是如何在内核内被管理的,然后来看看进程创建和调度的各种方式(在一个或多个处理器上),最后介绍进程的销毁。

在 Linux 内核内,进程是由相当大的一个称为?task_struct?的结构表示的。此结构包含所有表示此进程所必需的数据,此外,还包含了大量的其他数据用来统计(accounting)和维护与其他进程的关系(父和子)。对?task_struct?的完整介绍超出了本文的范围,清单 1 给出了?task_struct?的一小部分。这些代码包含了本文所要探索的这些特定元素。task_struct位于 ./linux/include/linux/sched.h。

volatile long state; void *stack; unsigned int flags; int prio,static_prio; struct list_head tasks; struct mm_struct *mm,*active_mm; pid_t pid; pid_t tgid; struct task_struct *real_parent; char comm[TASK_COMM_LEN]; struct thread_struct thread; struct files_struct *files; ...

};

在清单 1 中,可以看到几个预料之中的项,比如执行的状态、堆栈、一组标志、父进程、执行的线程(可以有很多)以及开放文件。我稍后会对其进行详细说明,这里只简单加以介绍。state?变量是一些表明任务状态的比特位。最常见的状态有:TASK_RUNNING?表示进程正在运行,或是排在运行队列中正要运行;TASK_INTERRUPTIBLE?表示进程正在休眠、TASK_UNINTERRUPTIBLE?表示进程正在休眠但不能叫醒;TASK_STOPPED?表示进程停止等等。这些标志的完整列表可以在 ./linux/include/linux/sched.h 内找到。

flags?定义了很多指示符,表明进程是否正在被创建(PF_STARTING)或退出(PF_EXITING),或是进程当前是否在分配内存(PF_MEMALLOC)。可执行程序的名称(不包含路径)占用?comm(命令)字段。

每个进程都会被赋予优先级(称为?static_prio),但进程的实际优先级是基于加载以及其他几个因素动态决定的。优先级值越低,实际的优先级越高。

tasks?字段提供了链接列表的能力。它包含一个?prev?指针(指向前一个任务)和一个?next?指针(指向下一个任务)。

进程的地址空间由?mm?和?active_mm?字段表示。mm?代表的是进程的内存描述符,而?active_mm?则是前一个进程的内存描述符(为改进上下文切换时间的一种优化)。

thread_struct?则用来标识进程的存储状态。此元素依赖于 Linux 在其上运行的特定架构,在 ./linux/include/asm-i386/processor.h 内有这样的一个例子。在此结构内,可以找到该进程自执行上下文切换后的存储(硬件注册表、程序计数器等)。

在 Linux 内虽然进程都是动态分配的,但还是需要考虑最大进程数。在内核内最大进程数是由一个称为max_threads?的符号表示的,它可以在 ./linux/kernel/fork.c 内找到。可以通过 /proc/sys/kernel/threads-max 的 proc 文件系统从用户空间更改此值。

现在,让我们来看看如何在 Linux 内管理进程。在很多情况下,进程都是动态创建并由一个动态分配的?task_struct?表示。一个例外是?init?进程本身,它总是存在并由一个静态分配的?task_struct?表示。在 ./linux/arch/i386/kernel/init_task.c 内可以找到这样的一个例子。

Linux 内所有进程的分配有两种方式。第一种方式是通过一个哈希表,由 PID 值进行哈希计算得到;第二种方式是通过双链循环表。循环表非常适合于对任务列表进行迭代。由于列表是循环的,没有头或尾;但是由于?init_task?总是存在,所以可以将其用作继续向前迭代的一个锚点。让我们来看一个遍历当前任务集的例子。

任务列表无法从用户空间访问,但该问题很容易解决,方法是以模块形式向内核内插入代码。清单 2 中所示的是一个很简单的程序,它会迭代任务列表并会提供有关每个任务的少量信息(namepid?和?parent?名)。注意,在这里,此模块使用?printk?来发出结果。要查看具体的结果,可以通过?cat?实用工具(或实时的?tail -f /var/log/messages)查看 /var/log/messages 文件。next_task?函数是 sched.h 内的一个宏,它简化了任务列表的迭代(返回下一个任务的?task_struct?引用)。

#include #include

int init_module( void )
{
/ Set up the anchor point /
struct task_struct *task = &init_task;

(编辑:衡阳站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读