第三章 Unix/Linux进程管理
3.1——3.2多任务处理、进程
多任务处理:多任务处理指的是机器同时进行几项独立活动的能力。在计算机技术中,多任务处理是通过在不同任务之间切换实现的。虽然在一个时间点,CPU只能执行一个任务,但是通过快速的切换,就会给人一种同时执行所有任务的错觉。这种逻辑并行性就叫做“并发”。
进程:在操作系统中,任务也称为进程,执行映像定义为包含代码、数据和堆栈的存储区,那么进程就是对映像的执行。
PROC结构体:在操作系统知识中我们学习过,进程的状态用一个独特的数据结构表示,叫做进程控制块(PCB)。在Liunx中也可以称为PROC结构体。PROC结构体包含某个进程的所有信息。
PROC结构体可详细定义如下:
typedef struct proc{
struct proc *next; //指向下一个PROC结构体的指针
int *ksp; //存储的sp
int pid; //进程ID(PID)
int status; //父进程的PID
int priority; //进程调度优先级
int kstack [SSIZE]; //进程执行堆栈
}PROC;
在一个单CPU系统中,一次只能执行一个进程。操作系统内核通常会使用正在运行的或当前的全局变量PROC指针,指向当前正在执行的PROC。
3.3 多任务处理系统
多任务处理系统,简称MT(Multi Task)。
可以用多个代码文件来描述MT原理。
type.h文件
文件中定义系统常数、简单的进程表示。
/*********** type.h file ************/
#define NPROC 9
#define SSIZE 1024
// PROC status
#define FREE 0
#define READY 1
#define SLEEP 2
#define ZOMBIE 3
typedef struct proc{
struct proc *next;
int *ksp;
int pid;
int status;
int priority;
int kstack [SSIZE];
}PROC;
可以看到,文件中定义了4中状态的系统常数,对应操作系统进程中的不同状态。
ts.s文件
此文件为汇编代码,实现上下文切换。
#-------------- 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文件完成数据结构中链表、队列等数据结构的定义和相关操作,以实现进程管理的相关需求。
/******************************* 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文件
t.c文件定义MT系统数据结构、系统初始化代码和进程管理函数。其中包括有退出、切换执行等操作,可以进行学习和模拟。
3.4~3.6 进程同步、进程终止
睡眠模式
当进程需要某些当前没有的东西的时候,就会进入休眠状态。
唤醒操作
调用kwakeup()就可以唤醒一个进程。此时,正在休眠的一个程序得到了需要的资源,继续执行其操作。
进程终止
进程完成后,就会终止或死亡。进程会以两种方式终止:
正常终止:进程自行调用结束函数exit(value)进行终止。
异常终止:进程因为某个信号而异常终止。
终止时,都会调用kexit()
。
INIT进程P1:有非常重要作用
①它是除了P0之外所有进程的祖先,所有登录进程都是它的子进程。
②它管理所有没有父进程的进程。(他就像孤儿院的院长,所有孤儿都叫他爸爸)。
③它不停寻找僵尸进程,并终止他们(埋葬它们死亡的空壳)
3.7~3.8 Unix/Linux中的进程
操作系统启动时,内核会强行创建PID=0的初始进程,然后系统执行P0。系统挂载文件,然后初始化完成后,复刻出子进程P1。
P1运行时,执行映像更改为INIT程序,复刻出更多子进程,用于提供系统服务,这样的进程成为守护进程。
登录进程:登录后进程打开三个文件流,分别是stdin
、stdout
、stderr
。
I/O重定向
sh进程有三个用于终端I/O的文件流:stdin(标准输入)、stdout(标准输出)、stderr(标准错误)。其文件描述符分别对应0、1、2。
在执行scanf("%s", &item);时,就会从stdin读入,如果其FILE结构体fbuf[]为空,它就会向Linux内核发出read系统调用,从终端/dev/ttyX或为终端/dev/pts/#上读入。
网上查到的I/O重定向符号和作用图
3.10 管道
管道是用于进程交换数据的单向进程间通信的通道。管道有一个输入端、一个输出端。在之前我们使用man -k | grep xx时,就用到管道的功能。
管道的使用可以通过程序完成,也可以在命令行中处理完成。
实践内容
在进程间尝试管道操作
在OpenEuler中参考书中代码,尝试实践管道操作
编译运行后,得到结果:
重定向实现文件内容排序
使用sort和命令行的重定向完成,将1.txt中的内容排序后存到2.txt中。
使用命令sort <1.txt >2.txt
完成。
排序后的2.txt
chatgpt