zoukankan      html  css  js  c++  java
  • 第三章学习笔记

    第三章学习笔记

    第三章 进程管理

    1.多任务处理

    • 多任务处理指的是同时进行几项独立活动的能力。、在计算机技术中,多任务处理指的是同时执行几个独立的任务。在单处理器(单CPU)系统中,一次只能执行一个任务。多任务处理是通过在不同任务之间多路复用CPU的执行时间来实现的,即将CPU执行操作从一个任务切换到另一个任务。不同任务之间的执行切换机制称为上下文切换,将一个任务的执行环境更改为另一个任务的执行环境。如果切换速度足够快,就会给人一种同时执行所有任务的错觉。这种逻辑并行性称为“并发”。在有多个CPU或处理器内核的多处理器系统中,可在不同CPU上实时、并行执行多项任务。此外,每个处理器也可以通过同时执行不同的任务来实现多任务处理。多任务处理是所有操作系统的基础。总体上说,它也是并行编程的基础。

    2.进程的概念

    • 操作系统是一个多任务处理系统。在操作系统中,任务也称为进程。在实际应用中,任务和进程这两个术语可以互换使用。在第2章中,我们把执行映像定义为包含执行代码、数据和堆栈的存储区。
    • 进程是对映像的执行。
    • 操作系统内核将一系列执行视为使用系统资源的单一实体。系统资源包括内存空间以及最重要的CPU时间。在操作系统内核中,每个进程用一个独特的数据结构表示,叫作进程控制块(PCB)或任务控制块(TCB)等。在本书中,我们直接称它为PROC结构体。与包含某个人所有信息的个人记录一样,PROC结构体包含某个进程的所有信息在实际操作系统中,PROC结构体可能包含许多字段,而且数量可能很庞大。首先,我们来定义一个非常简单的PROC结构体来表示进程。
    typedef struct proct{
    struct proc *next; 	// next proc pointer 
    int		ksp;  	// saved sp: at byte offset 4 
    int		pid; 	// process ID 
    int		ppid;	// parent process pid 
    int		status; 	// PROC status=FREE|READY, etc.
    int		priority;  	// scheduling priority 
    int		kstack[1024]; 	// process execution stack 
    
    }PROC;
    
    
    

    3.多任务处理系统

    1. type.h文件
    • type.h文件定义了系统常数和表示进程的简单PROC结构体
    /*********** 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;
    
    1. ts.s文件
    • ts.s在32位GCC汇编代码中可实现进程上下文切换
    #------------- ts,s file 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|
    
    #               -2   -3  -4  -5  -6  -7   -8  -9  -1
    
    1. 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
    ");
    
    }
    
    
    1. t.c文件
    • t.c文件定义MT系统数据结构、系统初始化代码和进程管理函数。
    1. 多任务处理系统代码介绍
    • (1)虚拟CPU:MT系统在Linux下编译链接为gcc -m32 t.c ts.s

    • (2)init():当MT系统启动时,main()函数调用init()以初始化系统。

    • (3)P0调用kfork()来创建优先级为1的子进程P1,并将其输入就绪队列中。

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

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

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

    • (7).3 tswitch()中的RESUME函数

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

    • (9)body():所有创建的任务都执行同一个body()函数。

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

    • (11)运行多任务处理(MT)系统

    4.进程同步

    1. 睡眠模式
    • 为实现休眠操作,我们可以在 PROC结构体中添加一个event字段,并实现ksleep(int event)函数,使进程进入休眠状态。我们将假设对 PROC结构体进行修改以包含加粗显示的添加字段。
    typedef struct proc{
    
    struct proc *next;
    
    int*ksp;
    
    int pid;
    
    int ppid;
    
    int status;
    
    int priority;
    
    int event;
    
    int exitCode;
    
    struct proc *child;
    
    struct proc *sibling;
    
    struct proc *parent;
    
    int kstack[1024];
    
    }PROC;
    
    1. 唤醒操作
    • 当某个等待时间发生时,另一个执行实体(可能是某个进程或中断处理程序)将会调用 kwakeup(event)。唤醒正处于休眠状态等待该事件值的所有程序。如果没有任何程序休眠等待该程序,kwakeup()就不工作,即不执行任何操作。Kwakeup()的算法:
    /********** Algorithm of kwakeup(int event)*********/
    
    // Assume SLEEPing proCs are in a global sleepiist
    
    for each PROC *p in sleepList do {
    
    if (p->event == event){
    
    delete D from sleepLiBt;
    
    p->8tatu8 = READY;
    
    enqueue(EreadyQueue,p);
    
    }
    
    }
    

    5.进程终止

    • 正常终止:进程调用exit(value),发出 exit(value)系统调用来执行在操作系统内核

    中的 kexit(value),这就是我们本节要讨论的情况。

    • 异常终止:进程因某个信号而异常终止。信号和信号处理将在后面第6章讨论。

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

    6.MT系统中的进程管理

    • 完善基础MT系统,实现MT系统的进程管理函数:
    1. 用二叉树的形式实现进程家族树。

    2. 实现 ksleepO()和kwakeup()进程同步函数。

    3. 实现kexit()和kwait()进程管理函数。

    4. 添加"w"命令来测试和演示等待操作。

    7.Unix/Linux中的进程

    1. 守护进程
    syslogd: log daemon process
    
    inetd :Internet service daemon process
    
    httpd : HTTP server daemon process
    
    etc.
    
    1. 进程的执行模式
    • 中断:中断是外部设备发送给 CPU的信号,请求CPU服务。

    • 陷阱:陷阱是错误条件,例如无效地址、非法指令、除以0等、这些错误条件被CPU识别为异常,使得CPU进入 Kmode 来处理错误。

    • 系统调用:系统调用(简称syscall)是一种允许Umode 进程进入Kmode 以执行内核函数的机制。如果发生错误,外部全局变量 errno(在errno. h中)会包含一个ERROR代码,用于标识错误。用户可使用库函数perror( "error message");

    9.I/O重点向

    1. fork()操作:
    2. 进程终止
    • 正常终止:回顾前面的内容,我们知道,每个C程序的 main()函数都是由C启动代码 crt0.o调用的。如果程序执行成功,main()最终会返回到 crt0.o,调用库函数 exit((0)来终止进程。首先,exit(value)函数会执行一些清理工作,如刷新 stdout、关闭I/O流等。然后,它发出一个_exit(value)系统调用,使进入操作系统内核的进程终止。
    • 异常终止:在执行某程序时,进程可能会遇到错误,如非法指令、越权、除零等,这些错误会被 CPU识别为异常。当某进程遇到异常时,它会进入操作系统内核。内核的异常处理程序将陷阱错误类型转换为一个函数,称为信号,将信号传递给进程,使进程终止。

    10.管道

    1. 管道是用于进程交换数据的单向进程间通信通道。管道有一个读取端和一个写入端。可从管道的读取端读取写入管道写入端的数据。自从管道在最初的Unix 中首次出现以来,已经被用于几乎所有的操作系统中,有许多变体。一些系统允许双向管道,在双向管道上,数据可以双向传输。普通管道用于相关进程。命名管道是不相关进程之间的 FIFO通信通道。但是,如果管道不再有读进程,写进程必须将这种情况视为管道中断错误,并中止写入。
    2. Unix/Linux中的管道编程
    • 管道中断状况并不具有对称性。这是一种只有读进程没有写进程的通信通道。实际上,管道并未中断,因为只要管道有数据,读进程就仍可继续读取。下面的程序演示了Unix/Linux中的管道。
    #include <stdio.h>
    
    
    #include <stdlib.h>
    
    
    #include <string.h>
    
    
    int pd[2],n,i;
    
    
    char line[256];
    
    
    int main()
    
    
    {
    
    
    pipe(pd);
    
    
    printf("pd=[$d,%d]
    ",pd[0],pd[1]);
    
    
    if (fork(){
    
    
    printf("parent $d close pd[0]
    ",getpid());
    
    
    close(pd[0]);  // parent as pipe WRITER
    
    
    while(i++ <10){    // parent writes to pipe 10 times
    
    
    printf("parent 8d writing to pipe
    ",getpid());
    
    
    n = write(pd[1],"I AM YOUR PAPA",16);
    
    
    printf("parent %d wrote %d bytes to pipe
    ",getpid(),n);
    
    
    }
    
    
    printf("parent $d exit
    ",getpid());
    
    
    }
    
    
    else{
    
    
    printf("child $d close pd[1]
    ",getpid());
    
    
    close(pd[1]); // child as pipe READER
    
    
    while(1) {
    
    
    // child read from pipe
    
    
    printf("child %d reading from pipe
    ",getpid());
    
    
    if((n = read(pd[0],line,128))){ // try to read 128 bytes
    
    
    line[n]=0;
    
    
    printf("child read $d bytes from pipe: 8s
    ",n,line);
    
    
    }
    
    
    else // pipe has no data and no writer
    
    
    exit(0);;
    
    
    }
    
    
    }
    
    
    }
    
  • 相关阅读:
    java网络爬虫爬虫小栗子
    浮点数精确表示
    使用yum安装CDH Hadoop集群
    判断奇数,java陷阱
    Long型整数,缄默溢出
    java基础知识点
    java常用指令
    Codeforces Round #275 (Div. 2) D
    区间dp的感悟
    Codeforces Round #386 (Div. 2) C D E G
  • 原文地址:https://www.cnblogs.com/zhangwenying/p/15452719.html
Copyright © 2011-2022 走看看