Download presentation
Presentation is loading. Please wait.
Published by阴 山 Modified 8年之前
1
1 张惠娟 副教授 Ms.zhj@163.com Linux 进程管理
2
2 内容 进程组成 进程环境 进程管理内容 进程控制块 进程状态 进程调度 进程控制 进程通信
3
3 进程组成 Linux 是一个多任务多用户操作系统,采用进 程模型。 进程都具有一定的功能和权限,运行在各自独 立的虚拟地址空间,彼此独立,且通过通信 机制实现同步互斥,通过调度程序实现合理 调度。
4
4 进程组成 正文段 存放进程要运行的程序,描述了进程要完成的功能 用户数据段 存放正文段在执行时所需要的数据和工作区 系统数据段 存放了进程的控制信息,其中最重要的数据结构 是 task_struct 。 进程组成
5
5 进程环境 Linux 进程有两种状态:内核态和用户 态 核心态又称系统态 Linux 在执行内核程序时是处于核心态下 用户态是进程的普通执行状态 一个进程在运行过程中,总是在两种执行状态之 间不断地转换。
6
6 进程虚拟地址空间分为:用户空间和系统空间。 用户空间 用户进程本身的程序和数据(可执行映象) 进程运行用户程序时使用的堆栈,即进程堆栈。 系统对进程进行控制和管理的信息,如进程控制块等 系统空间 内核被映射到所有进程的系统空间中。 只允许进程在核心态下访问。进程运行在用户态下时, 不允许直接访问系统空间。 进程只能通过系统调用转换为核心态后,才能访问系统 空间 进程环境
7
7 进程上下文 系统提供给进程处于动态变化的运行环境总和称为进 程上下文 系统上下文 系统完成自身任务时的运行环境称为系统上下文 内核在系统上下文中执行时不会阻塞。
8
8
9
9 进程管理内容 进程管理由进程控制块、进程调度、中断处 理、任务队列、定时器, bottom half 队列、 系统调用、进程通信等部分组成。 进程管理是 Linux 存储管理,文件管理,设备 管理的基础。
10
10 进程控制块 进程控制块是 Linux 系统最复杂的数据 结构之一。 Linux 在内存空间中开辟了一个专门区域存 放所有进程的进程控制块。 系统初始化后,建立第一个 task_struct 数 据结构 INIT_TASK 。 新进程创建时,系统从内存分配新 task_struct ,占据 1680 个字节。
11
11 进程状态和标志 进程标识 进程控制块
12
12 进程的族亲关系 进程控制块
13
13 进程间链接信息 进程调度信息 进程控制块
14
14 进程的时间信息 进程的虚存信息 进程控制块
15
15 进程的文件信息 与进程间通信有关的信息 进程控制块
16
16 其它信息 进程控制块
17
17 进程状态 定义了六种状态进程状态 #define TASK_RUNNING0 #define TASK_INTERRUPTIBLE1 #define TASK_UNINTERRUPTIBLE2 #define TASK_ZOMBIE4 #define TASK_STOPPED8 #define TASK_SWAPPING16
18
18
19
19 进程调度 调度方法 调度策略 调度参数 调度方法 调度时机
20
20 调度方法 Linux 进程调度方式 采用抢占调度方式 (内核不抢占) 进程分为普通进程和实时进程,分别采 用不同的调度策略,实时进程的优先级 高于普通进程。 进程调度
21
21 调度策略 进程调度
22
22 调度参数 policy 进程调度策略,可通过系统调用 sys_sched_setscheduler() 更改 ( kernel/sched.c )。 SCHED_OTHER 非实时进程,基于优先级的 轮转法 SCHED_FIFO 实时进程,用先进先出算法 SCHED_RR 实时进程,用基于优先权的轮转 法 进程调度
23
23 priority 进程优先级(静态),给出进程每次获取 cpu 后可使用的时间(按 jitty 计算)。通过系统调 用 sys_setpriority() 改变。 Linux 的基准时间( kernel/timer.c )。系统初 始化时清零,以后每隔 10ms 由时钟中断服务 程序, do_timer 增 1 。 进程调度
24
24 rt_priority 实时进程的优先级,可通过系统调用 sys_sched_setscheduler() 改变. Counter 进程动态优先级表示进程当前还可运行多久 进程开始运行时被赋为 priority 值,以后,每隔 一个 tick (时钟中断)递减 1 ,减到 0 时引起新 一轮调度。 重新调度将从 run-queue 队列中选出 counter 值 最大的就绪进程获得 cpu 。 进程调度
25
25 进程调度 调度方法 采用动态优先级法,调度对象是可运行队列。 进程在运行中, counter 代表动态优先级。 Linux 采取了加权的方法来保证实时进程优先于 普通进程。普通进程的权值就是它的 counter 的 值,实时进程的权值是它的 rt_priority 的值加 1000 。 调度过程中,调度程序检查可运行队列中所有进 程的权值,选择其中权值最大的进程做为下一个 运行进程。
26
26 static inline int goodness(struct task_struct * p, struct task_struct * prev, int this_cpu) { int weight; if (p->policy != SCHED_OTHER) return 1000 + p->rt_priority; weight = p->counter; …… return weight; } 进程调度
27
27 调度时机 时机 1 :进程状态发生变化时 处于运行态下的进程要等待某种资源 运行态下的进程在程序执行完毕后,通过 调用内核函数 do_exit() 终止运行并转入僵 死态。 处于等待态的进程被唤醒后,将加入到可 运行队列中时 进程从运行态转入暂停态时 进程从暂停态成为可运行态时 进程调度
28
28 时机 2 当前进程时间片用完时 时机 3 进程从系统调用返回到用户态时 时机 4 中断处理后,进程返回到用户态时。 进程调度
29
29 进程控制 进程创建过程 进程状态间转换
30
30 进程创建过程 为新进程分配任务结构体内存空间 把父进程任务结构体拷贝到子进程任务结构体 为新进程在其虚拟内存建立内核堆栈 对子进程任务结构体中部分进行初始化设置 把父进程有关信息拷贝给子进程,建立共享关系 把子进程的 counter 设为父进程 counter 值的一半 把子进程加入到可运行队列中 结束 do_fork() 函数返回 PID 值 进程控制
31
31 创建过程具体描述 系统启动时创建第一个进程( 0 号进程) 此时,系统只有这一个进程:初始化进程,运行 在核心态 初始化结束时,初始进程启动一个核心进程: init 进程,也称为 1 号进程,然后执行空闲循环。 系统空闲时,调度程序运行这个空闲进程。这个 空闲进程的 task_struct 是唯一一个不是动态分配 而是在核心连接时静态定义的,为了不至于混淆, 叫做 init_task 。 进程控制
32
32 进程由 do_fork() 函数创建 int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) { 为新进程申请 PCB 空间 ; if ( 申请不到 ) 返回错误, 退出 ; 为新进程申请核心堆栈 ; if ( 核心堆栈申请不到 ) 返回错误, 退出 ; 为新进程在 Task 向量表中找到空闲位置 ; /* 复制父进程 current PCB 中的信息,继承资源 */ ; p = current; 进程控制
33
33 /* 为防止信号、定时中断误唤醒未创建完毕的进 程,将子进程的状态设成不可中断的 */ p->state = TASK_UNINTERRUPTIBLE; /* 跟踪状态和超级用户特权是没有继承性的,因为在 root 用户为 普通用户创建进程时,出于安全考虑这个普通用户的进程不允 许拥有超级用户特权。 */ p->flags &= ~ (PF_PTRACED|PF_TRACESYS|PF_SUPERPRIV); /* 将进程标志设成初建,但暂时不能运行,在进程第一次获得 CPU 时,内核将根据此标志进行一定操作 */ p->flags |= PF_FORKNOEXEC; 进程控制
34
34 开始 Task_struct 的初始化工作,如初始化进程时钟、 信号、时间等数据 ; 继承父进程所有资源 : 拷贝父进程当前打开的文件 ; 拷贝父进程在 VFS 的位置 ; 拷贝父进程的信号量 ; 拷贝父进程运行的内存 ; 拷贝父进程的线程 ; 初始化工作结束,父进程将其将其唤醒, 挂入 running 队列中,返回子进程的 pid; 进程控制
35
35
36
36 进程状态间转换
37
37 转换说明 sleep_on(): TASK_RUNNING->TASK_UNINTERRUPTIBLE 拥有 CPU 的进程申请资源无效时,通过 sleep_on() ,将 进程从 TASK_RUNNING 切换到 TASK_UNINTERRUPTIBLE 状态。 sleep_on() 函数作用就是将 current 进程的状态置成 TASK_UNINTERRUPTIBLE, 并加到等待队列中。 一般来说引起状态变成 TASK_UNINTERRUPTIBLE 的资 源申请,都是对一些硬件资源的申请,如果得不到这些 资源,进程将不能执行下去,不能由 signal 信号或时钟 中断唤醒回到 TASK_RUNNING 状态。 进程状态间转换
38
38 interruptible_sleep_on() : TASK_RUNNING->TASK_INTERRUPTIBLE 拥有 CPU 的进程申请资源无效时,通过该函数将进程从 TASK_RUNNING 切换到 TASK_INTERRUPTIBLE 状态。 interruptible_sleep_on() 函数作用就是将 current 进程的状态 置成 TASK_INTERRUPTIBLE, 并加到等待队列中。 处于 TASK_INTERRUPTIBLE 状态的进程可在资源有效时被 wake_up() 、 wake_up_interruptible() 或 wake_up_process() 唤醒,或收到 signal 信号以及时间中断后被唤醒。 进程状态间转换
39
39 sleep_on_timeout() : TASK_RUNNING- >TASK_UNINTERRUPTIBLE interruptible_sleep_on_timeout (): TASK_RUNNING->TASK_INTERRUPTIBLE 虽然在申请资源或运行中出现了某种错误,但是 系统仍然给进程一次重新运行的机会。调用该函 数将进程从 TASK_RUNNING 切换到 TASK_INTERRUTIBLE 状态,并等待规定的时间 片长度, 再重新试一次。 进程状态间转换
40
40 wake_up() TASK_UNINTERRUPTIBLE-> TASK_RUNNING TASK_INTERRUPTIBLE-> TASK_RUNNING 处于 TASK_UNINTERRUPTIBLE 状态的进程不能由 signal 信号 或时钟中断唤醒,只能由 wake_up() 或 wake_up_process() 唤醒。 wake_up() 函数的作用是将 wait_queue 中所有状态为 TASK_INTERRUPTIBLE 或 TASK_UNINTERRUPTIBLE 的 进程 状态置为 TASK_RUNNING, 并将它们都放 running 队列中去,即唤醒所有等待在该队列上的进程 。 进程状态间转换
41
41 进程通信机制 支持大量的进程通信机制 锁机制 信号 管道 消息队列 信号量 共享内存
42
42 信号 操作系统通过信号向进程发送异步事件信号。 当一个事件发生时,如果需要通知进程,则系 统就为其生成一个信号,进程在接受到信号后, 可采取适当动作来处理信号。 在 linux 系统中,内核用一个字代表所有信号, 信号种类的树目和具体平台有关,如 32 位、 64 位。 信号是内核不可分割的一部分,不象其他 ipc , 是可选的。 进程通信机制
43
43 进程对信号的操作 忽略信号 阻塞信号 由进程处理信号 由内核进行默认处理 进程通信机制
44
44 管道( pipe ) 有名管道 一般为系统特殊文件方式, 使用的进程之间不一定 要有父子关系或兄弟关系. 无名管道 一般为内存方式, 使用的进程之间一定要有父子关 系或兄弟关系. 无名管道实现方法 两个 file 数据结构指向同一个临时 VFS INODE 节点 (本身指向内存中的一个物理页)实现。 进程通信机制
45
45 f_mode … f_inode f_op … f_mode … f_inode f_op … 写操作 读操作 数据页面 VFS inode 进程 1 的 file 结构进程 2 的 file 结构 进程通信机制
46
46 pipe_write() \fs\pipe.c 中定义了 pipe_write 函数 把字节从进程地址空间拷贝到共享数据页 如果管道被读进程锁定或者空间不够,当前进程睡眠,放 在管道 INODE 节点等待队列中,并调用调度程序,运行 另外一个进程。 写过程可以中断,所以可以接收信号。当管道中有足够空 间写数据或者锁定解除,写进程就会被读进程唤醒。 数据写完之后, VFS INODE 节点锁定解除,管道 INODE 节点的等待队列中的所有读进程都会被唤醒。 进程通信机制
47
47 pipe_write() 和写过程相似。 允许进行非阻塞读,即如果没有数据可读或者 管道被锁定,返回一个错误。这意味着进程会 继续运行。 另一种方式是在管道的 INODE 节点的等待队列 中等待,直到写进程完成。 如果管道进程都完成操作,管道 INODE 节点和 相应的共享数据页被废弃。 进程通信机制
Similar presentations