linux多进程编程(2)

2018-12-29 20:22

重庆邮电大学移通学院毕业设计(论文) 第1章 Linux进程相关内核代码简要分析

第1章 Linux进程相关内核代码简要分析

1.1 基本概念

1.1.1 进程

进程是任何多任务操作系统中的基本概念。通常把进程定义为一个应用程序运行实例。如果当前有n个用户同时运行一个程序,例如mplayer,那么就有n个独立的进程(尽管它们共享同一段可执行代码)

1.1.2 轻量级进程和线程

为什么这个部分要将轻量级进程和线程同时提出。因为在Linux系统很少使用线程的概念。为什么Linux要很少使用线程的概念。因为线程在处理一些任务的时候性能并不令人满意。例如:现在我们有一个GUI(Graphical User Interface,简称 GUI,又称图形用户接口)程序,程序分为两部分,其一是图形处理部分,其二是后台数据处理。可以将这两部分分为两个线程,如果这个程序是一个单独的进程,就会出现这样的问题。图形处理线程会常常阻塞等待用户的各种操作,这样就会导致数据处理的线程也会阻塞。相反,图形处理线程要使用非常复杂的非阻塞技术来确保进程是运行的。

为了解决上述问题,Linux传奇式的引入了一个轻量级进程的概念,此概念只存在在Linux系统中。轻量级进程是线程的替代。轻量级进程其实就是一个普通的进程,不同的是几个轻量级进程之间可以共享资源,如地址空间,打开的文件。只要其中一个修改共享资源,另一个就会立即查看这种修改。当两个轻量级进程访问共享资源是就必须同步它们。

虽然Linux很少使用线程的概念,但任然提供了线程的支持,具体可参考pthread.h。

6

重庆邮电大学移通学院毕业设计(论文) 第1章 Linux进程相关内核代码简要分析

1.2进程的静态结构

1.2.1进程描述符[1][3]

为了管理进程,内核必须对每个进程做清晰的描述。Linux内核代码中进程描述数据结构task_struct存放在include/linux/sched.h[1][3]头文件中。

Linux进程描述符中所包含的信息有进程标识符(PID),进程所占内存区域,相关文件的文件描述符,安全信息,进程环境,信号处理,资源安排,同步处理,和进程状态几个方面[1][3]。

task_struct结构中的的几个特殊成员:

进程状态

定义在sched.h头文件中

#define TASK_RUNNING 0 //正在运行中的进程 #define TASK_INTERRUPTIBLE 1 列

#define TASK_UNINTERRUPTIBLE 其他进程中断

#define TASK_STOPPED 4 //进程暂停,通过其他信号才能唤醒 #define TASK_TRACED 8 //进程处理跟踪状态

#define EXIT_ZOMBIE 16 //僵尸状态task数组中任然有个tast_struct数据结构项,它只等待父进程将他释放

#define EXIT_DEAD 32 //最终状态,父进程发出wait4()调用或waitpid()调用,进程由系统删除

2 //等待队列中的进程,等待资源有效时唤醒,但不可被

//等待队列中的进程,等待资源有效时唤醒进入就绪队

2.进程标志位(flags)

#define PF_ALIGNWARN 0x00000001 #define PF_STARTING #define PF_EXITING #define PF_DEAD

0x00000002 0x00000004 0x00000008

/* 打印对齐警告短信息 */ /* 进程被创造 */ /* 标志进程开始关闭 */ /* 僵尸进程 */

/* 进程刚创建但没有运行 */ /* 使用超级用户权限 */ /* 标志是否清空core文件 */ /* 标志进程被信号signal终止 */ /* 标志进程正在分配内存 */ /* 磁盘回写 */

/* 如果不进行初始化的fpu必须在使用前 */

#define PF_FORKNOEXEC 0x00000040 #define PF_SUPERPRIV 0x00000100 #define PF_DUMPCORE #define PF_SIGNALED #define PF_MEMALLOC #define PF_FLUSHER

0x00000200 0x00000400 0x00000800 0x00001000

#define PF_USED_MATH 0x00002000

#define PF_FREEZE 0x00004000 /* 进程被暂停 */

7

重庆邮电大学移通学院毕业设计(论文) 第1章 Linux进程相关内核代码简要分析

#define PF_NOFREEZE 0x00008000 /* 进程未被暂停 */ #define PF_FROZEN 0x00010000 /* 系统暂停 */ #define PF_FSTRANS 0x00020000 /* 读/写文件系统 */ #define PF_KSWAPD 0x00040000 /* 创建swap */ #define PF_SWAPOFF 0x00080000 /* 清空swap */ #define PF_LESS_THROTTLE 0x00100000 /* 内存清空 */ #define PF_SYNCWRITE 0x00200000 /* 我在做一个同步写 */ #define PF_BORROWED_MM 0x00400000 /* 我是一个kthread做use_mm */

3.跟踪标志(unsigned long ptrace)

#define PF_PTRACED 0x00000010 /* 进程正在被跟踪 */ #define PF_TRACESYS 0x00000020 /* 正在跟踪系统调用 */

4.进程优先级

int prio优先级,在0~MAX_PRIO-1之间(MAX_PRIO为140),其中0~MAX_RT_PRIO-1(MAX_RP_PRIO

100)属于实时进程范围,

MAX_RT_PRIO~MAX_PRIO为非实时进程,数值越大,优先级越小。

5.prio_array_t *array

优先级数组,将进程优先级为序号的数组。 实时优先级 unsigned long rt_priority

rt_priority给出实时优先级,rt_priority+1000给出进程每次获得CPU后,可以使用的时间,实时进程优先级可以由系统调用sys_sched_setschedule()改变。

1.3进程的创建[1][8]

让我们不妨亲自看看如何从用户空间创建一个进程。用户空间任务和内核任务的底层机制是一致的,因为二者最终都会依赖于一个名为 do_fork 的函数来创建新进程。在创建内核线程时,内核会调用一个名为 kernel_thread 的函数(参见 ./linux/arch/i386/kernel/process.c),此函数执行某些初始化后会调用 do_fork。

8

重庆邮电大学移通学院毕业设计(论文) 第1章 Linux进程相关内核代码简要分析

图1.1 进程创建

从图1.1中,可以看到 do_fork 是进程创建的基础。可以在 ./linux/kernel/fork.c 内找到 do_fork 函数。

do_fork 函数首先调用 alloc_pidmap,该调用会分配一个新的 PID。接下来,do_fork 检查调试器是否在跟踪父进程。如果是,在 clone_flags 内设置 CLONE_PTRACE 标志以做好执行 fork 操作的准备。之后 do_fork 函数还会调用 copy_process,向其传递这些标志、堆栈、注册表、父进程以及最新分配的 PID。

新的进程在 copy_process 函数内作为父进程的一个副本创建。此函数能执行除启动进程之外的所有操作,启动进程在之后进行处理。copy_process 内的第一步是验证 CLONE 标志以确保这些标志是一致的。如果不一致,就会返回 EINVAL 错误。接下来,询问 Linux Security Module (LSM) 看当前任务是否可以创建一个新任务。

接下来,调用 dup_task_struct 函数(在 ./linux/kernel/fork.c 内),这会分配一个新 task_struct 并将当前进程的描述符复制到其内。在新的线程堆栈设置好后,一些状态信息也会被初始化,并且会将控制返回给 copy_process。控制回到 copy_process 后,除了其他几个限制和安全检查之外,还会执行一些常规管理,包括在新 task_struct 上的各种初始化。之后,会调用一系列复制函数来复制此进程的各个方面,比如复制开放文件描述符(copy_files)、复制符号信息(copy_sighand

9

重庆邮电大学移通学院毕业设计(论文) 第1章 Linux进程相关内核代码简要分析

和 copy_signal)、复制进程内存(copy_mm)以及最终复制线程(copy_thread)。

之后,这个新任务会被指定给一个处理程序,同时对允许执行进程的处理程序进行额外的检查(cpus_allowed)。新进程的优先级从父进程的优先级继承后,执行一小部分额外的常规管理,而且控制也会被返回给 do_fork。在此时,新进程存在但尚未运行。do_fork 函数通过调用 wake_up_new_task 来修复此问题。此函数(可在 ./linux/kernel/sched.c 内找到)初始化某些调度程序的常规管理信息,将新进程放置在运行队列之内,然后将其唤醒以便执行。最后,一旦返回至 do_fork,此 PID 值即被返回给调用程序,进程完成。

1.4 Linux进程调度[1][3][8][9][11]

1.4.1 总述

2.6 调度系统从设计之初就把开发重点放在更好满足实时性和多处理机并行性上,并且基本实现了它的设计目标。新调度系统的特性为如下几点:

1.交互式作业优先

2.轻载条件下调度/唤醒的高性能 3.公平共享 4.基于优先级调度 5.高 CPU 使用率 6.SMP 高效亲和

7.实时调度和 cpu 绑定等调度手段

1.4.2 runqueque结构[1][3]

此结构定义在./linux/kernel/sched.c中,runpuepue中的prio_arrary_t *active,*expired,arrays[2]成员说明,此是这个结构中的关键数据结构,每个CPU队列按照时间片是否用完分为两部分,分别通过*active和*expired两个指针访问。active指向时间片没用完,当前可被调度的就绪进程;expired指向时间片用完的

10


linux多进程编程(2).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:七年级语文下册25.《短文两篇》导学案

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: