第三章

3.1~3.2多任务处理与进程

  • 多任务处理:

多任务处理指的是机器同时进行几项独立活动的能力。在计算机技术中,多任 务处理是通过在不同任务之间切换实现的。虽然在一个时间点,CPU只能执行一个任务,但是通过快速的切换,就会给人一种同时执行所有任务的错觉。这种逻辑并行性就叫做“并发”。


  • 进程:

操作系统中,任务也称为进程,执行映像定义为包含代码、数据和堆栈的存储区,那么进程就是对映像的执行。
操作系统内核将一系列执行视为使用系统资源的单一实体。系统资源包括内存空间、I/O设备以及最重要的CPU时间。在操作系统内核中,每个进程用一个独特的数据结构表示,叫作进程控制块(PCB)或任务控制块(TCB)等。在本书中,我们直接称它为PROC结构体。与包含某个人所有信息的个人记录一样,PROC结构体包含某个进程的所有信息在实际操作系统中,PROC结构体可能包含许多字段,而且数量可能很庞大。

3.3多任务处理系统

多任务处理系统,简称MT(Multi Task)。
可以用多个代码文件来描述MT原理。

  • type.h文件
    type.h文件定义了系统常熟和表示进程的简单PROC结构体.
#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;
  • ts.s文件
    ts.s在32位GCC汇编代码中可实现进程上下文切换
.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|

# -2   -3  -4  -5  -6  -7   -8  -9  -1
  • queue.c文件
    queue.c文件可实现队列和链表操作函数。
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系统数据结构、系统初始化代码和进程管理函数。
  • 多操作系统多架构什么意思 操作系统多任务处理_多任务处理


  • 多操作系统多架构什么意思 操作系统多任务处理_#define_02


  • 多操作系统多架构什么意思 操作系统多任务处理_多操作系统多架构什么意思_03


  • 多操作系统多架构什么意思 操作系统多任务处理_系统调用_04


  • 多操作系统多架构什么意思 操作系统多任务处理_#define_05

  • 多任务处理系统代码介绍
    (1) 虚拟CPU:MT系统在Linux下编译链接为
    gcc -m32 t.c ts.s
    然后运行a.out.整个MT系统在用户模式下作为Linux进程进行。在Linux进程中,我们创建了多个独立执行实体(叫作任务),并通过我们自己的调度算法将它们调度到Linux进程中运行。

(2) init():当MT系统启动时,main()函数调用init()以初始化系统。Init()初始化PROC结构体,并将它们输入freeList中。它还将readyQueue初始化为空。

(3) P0调用kfork()来创建优先级为的子进程P1,并将其输入就绪队列中。然后P0调用tswitch(),将会切换任务以运行P1.

(4) tswitch():tswitch()函数实现进程上下文切换。

(5) .1 tswitch中的SAVE函数:当正在执行的某个任务调用tswitch()时,它会把返回地址保存在堆栈上,并在汇编代码中进入tswitch()。

(6) .2 scheduler():在执行了tswitch()中的SAVE函数之后,任务调用scheduler()来选择下一个正在运行的任务。

(7) .3 tswitch()中的RESUME函数:当执行从scheduler()返回时,“运行”可能已经转而指向另一个任务的PROC。

(8) Kfork():kfork()函数创建一个子任务并将其输入readyQueue中。

(9) body():为便于演示,所有创建的任务都执行同一个body()函数。

(10) 空闲任务P0:P0的特殊之处在于它在所有任务中具有最低的优先级。

(11) 运行多任务处理(MT)系统:在Linux下,输入gcc -m32 t.c s.s 编译链接MT系统并运行所得到的a.out。

3.4进程同步

3.4.1睡眠模式

当某进程需要某些当前没有的东西时,例如申请独占一个存储区域、等待用户通过标准输入来输入字符等,它就会在某个事件值上进入休眠状态,该事件值表示休眠的原因。

3.4.2唤醒操作

多个进程可能会进入休眠状态等待同一个事件,这是很自然的,因为这些进程可能都需要同一个资源,例如一台当前正处于繁忙状态的打印机。

3.5进程终止

在操作系统中,进程可能终止或死亡,这是进程终止的通俗说法。如第二章所述,进程能以两种方式终止:

  • 正常终止:进程调用exit(value),发出_exit(value)系统调用来执行在操作系统内核中的kexit(value),这都是我们本节要讨论的情况。
  • 异常终止:进程因某个信号而异常终止。

在这两种情况下,当进程终止时,最终都会在操作系统内核中调用kexit()。

3.7Unix/Linux中的进程

进程的执行模式
1.中断:中断是外部设备发送给 CPU的信号,请求CPU服务。
2.陷阱:陷阱是错误条件,例如无效地址、非法指令、除以0等、这些错误条件被CPU识别为异常,使得CPU进入 Kmode 来处理错误。
3.系统调用:系统调用(简称syscall)是一种允许Umode 进程进入Kmode 以执行内核函数的机制。如果发生错误,外部全局变量 errno(在errno. h中)会包含一个ERROR代码,用于标识错误。用户可使用库函数 perror( "error message");
3.8进程管理的系统调用

3.9I/O重定向

1.文件流和文件描述符

如前所述,sh进程有三个用于终端I/O的文件流:stdin(标准输入)、stdout(标准输出)和stderr(标准错误)。每个流都是指向执行映像堆区中FILE结构体的一个指针。每个文件流对应Linux内核中的一个打开文件。每个打开文件都用一个文件描述符(数字)表示。

2.文件流I/O和系统调用

当进程执行库函数

scanf("%s",&item);

它会试图从stdin文件输入一个(字符串)项,指向FILE结构体。

3.重定向标准输入

如果我们用一个新打开的文件来替换文件描述符0,那么输入来自该文件而不是原始输入设备。

4,重定向标准输出

3.10管道

管道是用于进程交换数据的单向进程间通信的通道。管道有一个输入端、一个输出端。在之前我们使用man -k | grep xx时,就用到管道的功能。
管道的使用可以通过程序完成,也可以在命令行中处理完成。