Unix/Linux系统编程自学笔记-第三章:Unix/Linux进程管理
1、概念介绍
-
多任务处理
计算机技术概念中的多任务处理指的是同时执行若干独立任务。无论是在多处理机系统还是单处理机系统都可以实现多任务处理。对于单处理机系统,多任务处理的实现依靠着多路复用技术,通过上下文的快速切换实现逻辑上的多任务并行处理。这种并行性被称为并发。
-
进程的概念
进程是对映像的执行。一个进程是一个对资源的动态利用的过程,系统内核通过一个独特的数据结构来表示,它被称为进程控制块PCB或任务控制块TCB。在本章中直接称之为PROC结构体。
PROC的定义:
typedef struct proc{
struct proc *next; int *ksp;
int pid;
int ppid;
int status;
int priority;
int kstack[1024];
}PROC;
next:指向下一个PROC结构体的指针;
ksp字段是保存的堆栈指针,存储了放弃使用CPU的进程的上下文;
pid标识一个进程的ID编号;
ppid为父进程的编号;
status是进程的当前状态;
priority是进程的调度优先级;
kstack是进程执行时的堆栈。
2、多任务处理系统
多任务处理 在计算机技术中,多任务处理指的是同时执行几个独立的任务。在单处理器(单CPU)系统中,一次只能执行一个任务。多任务处理是通过在不同任务之间多路复用CPU的执行时间来实现的,即将CPU执行操作从一个任务切换到另一个任务。不同任务之间的执行切换机制称为上下文切换,将—个任务的执行环境更改为另一个任务的执行环境。如果切换速度足够快就会给人一种同时执行所有任务的错觉。这种逻辑并行忡称为 “并发”。在有多个CPU或处理器内核的多处理器系统中,可在不同CPU上实时、 并行执行多项任务。
-
type.h文件,定义了系统常数和简单的PROC结构体:
/*********** type.h file ************/ #define NPROC 9 //numbers of PROC #define SSIZE 1024 //stack size = 4KB // PROC status #define FREE 0 #define READY 1 #define SLEEP 2 #define ZOMBIE 3 typedef struct proc{ struct proc *next; //next proc pointer int *ksp; //saved stack pointer int pid; //pid = 0 to NPROC-1 int ppid; //parent pid int status; //PROC status int priority; //scheduled priority int kstack [SSIZE]; //process stack }PROC;
-
ts.s文件,32汇编代码,用于实现上下文切换:
#-------------- ts.s file ---------------- .globl running,scheduler, tswitch tSwitch: SAVE: pushl %eax : pushl %ebx pushl %ecx pushl %edx pushl %ebp pushl %esi pushl %edi pushf1 movl running, Sebx mov1 # esp,4(%ebx) FIND: call scheduler RESUME: movl running,8ebx movl 4(%ebx),%esp popf1 popl %edi popl %esi popl %ebp popl %edx popl %ecx popl %ebx popl %eax ret # stack contents=|retPC|eax|ebx|ecx|edx|ebp|esi|edi|eflag| # -1 -2 -3 -4 -5 -6 -7 -8 -9
-
queue.c文件,可实现队列和链表操作函数:
/******************************* queue.c file *******************************/ int enqueue(PROC **queue,PROC *p) { PROC *q = *queue; if(q == 0 || p->priority> q->priority){ *queue = p; p->next = q; } else{ while(g->next && p->priority <= q->next->priority) q = q->next; p->next = q->next; q->next = p; } } PROC *dequeue (PROC **queue) { PROC *p = *queue; if (p) *queue =(*queue)->next; return p; } int printList(char *name,PROC *p) { printf("%s = ",name); while(p){ printf("[8d %d]->",p->pid,p->priority); p = p->next; } printf("NULL\n"); }
-
t.c文件,定义MT系统数据结构、系统初始化代码和进程管理函数:
/*********** t.c file of A Multitasking System ***********/ #include <stdio.h> #include "type.h" PROC proc[NPROC]; //NPROC PROCs PROC *freeList; //freeLists PROC *readyQueue; PROC *running; #include "queue.c" /*********************************************************** kfork() creats a child process and returns a chile pid, When scheduled to run , child PROC resumes to body; ***********************************************************/ int kfrok() {...} int kexit() //to exit {...} int do_kfork() {...} int do_switch() {...} int do_exit() {...} int body() //prcdess body function {...} int init() {...} int main() {...} int scheduler() {...}
3、进程同步与终止
-
睡眠模式
当某进程需要某些当前没有的东西时, 例如申请独占一个存储区域、 等待用户通过标准输人来输入字符等, 它就会在某个事件值上进入休眠状态, 该事件值表示休眠的原因。 为实现休眠操作, 我们可在 PROC 结构体中添加一个 event 字段, 并实现 ksleep(int event) 函数,使进程进人休眠状态。
-
唤醒操作
一个进程可能会进入休眠状态等待同一个事件,这是很自然的,因为这些进程可能都需要同一个资源,例如一台当前正处于繁忙状态的打印机。在这种情况下,所有这些进程都将休眠等待同一个事件值。当某个等待时间发生时,另一个执行实体(可能是某个进程或中断 处理程序)将会调用 kwakeup(event), 唤醒正处千休眠状态等待该事件值的所有程序。如果没有任何程序休眠等待该程序,kwakeup() 就不工作,即不执行任何操作。
-
进程终止
在操作系统中,进程会终结或死亡,即进程终止。进程终止有两种方式:
1、正常终止:调用结束函数exit(value)进行终止,由进程自身操作。
2、异常终止:进程因为某个信号而异常终止,最终会调用kexit()。
4、MT系统中的进程管理
MT系统管理函数的一般格式:
- 用二叉树实现的进程家族树
- 实现 ksleep() 和 kwakeup() 进程同步函数
- 实现 kexit() 和 kwait() 进程管理函数
- 添加 "w" 命令来进行测试或演示操作
5、Unix/Linux中的进程
-
进程的来源
当操作系统启动时,操作系统内核会强行创建一个 PID=0 的初始进程,即通过分配 PROC 结构体 (通常是proc[0])来初始化 PROC 的内容,并让运行指向 proc[0] ,然后它会挂载一个根文件系统,使得系统可以使用文件。在初始化后P0会复刻出子进程P1,并将进程切换为用户模式继续运行P1。 -
P1进程
P1进程也被称为INIT进程,因为P1开始运行后的执行映像被更改为了INIT程序。P1中的大部分子进程都是用来提供服务的,不进行用户交互,它们被称为守护进程。 -
登录进程
P1中用于用户登录的LOGIN进程,每个进程打开三个相关文件流(stdin、stdout 和 stderr),指向的是堆栈区中的FILE结构体。 -
进程的执行模式
Linux/Unix系统中的进程有内核模式(Kmode)和用户模(Umode)式两种。进程在两种模式下动态变化,内核模式下进程可以随意进入用户模式,但用户模式进入内核模式只有三种方法:
-
中断
外部设备发给CPU请求服务信号,在用户模式下的CPU将会响应该信号并中断进程,然后CPU进入内核模式处理中断。
-
陷阱
即错误条件,CPU识别到错误条件后会尽行异常处理,此时CPU会进入内核模式处理异常。
-
系统调用
系统调用只可在内核模式下使用,这将会使CPU进入内核模式。
-
6、I/O重定向
-
sh进程有三个用于终端I/O的文件流:
- stdin:标准输入,文件名描述符为0
- stdout:标准输出,文件描述符为1
- stderr:标准错误,文件描述符为2
-
重定向标准输入/输出
-
重定向标准输入
-
重定向标准输出
-
7、管道
管道可以实现进程间的单向数据交换,每个管道有一个输入端,一个输出 端。可以从管道的读取端读取写入管道写入端的数据。
-
管道命令处理
命令行有如下格式:
cmd1 | cmd2
其中的"|"符号就是管道符号,cmd1的输出会变成cmd2的输入。
-
命名管道
又称为FIFO,管道的名称以某种文件形式存储在文件系统之中,一旦命名后就会一直存在,直到使用rm或unlink将其删除。一个实例:
mknod mypepe p
或者:
int r=mknod("mypipe",S_IFIFO,0);
以上两种命令都可以在当前目录下创建一个名为mypipe的特殊文件,使用ls命令就可看到该文件,使用如下命令:
ls -l mypipe
即可显示管道链接的详细信息:
prw-r-r- 1 root root 0 time mypipe
文件类型p表示它是管道,连接数是1,大小为0。
chatgpt
2)