进程可以看成程序的执行过程,可以展示在当前时刻的执行状态。它是程序在一个数据集合上的一次动态执行的过程。这个数据集合通常包含存放可执行代码的代码段,存放初始化全局变量和初始化静态局部变量的数据段、用于调试的符号表、未初始化的全局变量和未初始化的静态局部变量的bss段,存放对象数据和临时变量以及数据层次结构的堆栈,系统资源等
       进程有多种状态,例如创建,就绪,执行,等待,终止 等。

为了实验简单,暂时只设置如下的进程状态:空闲状态,就绪,睡眠,僵尸状态。其中,僵尸状态值的是进程已经执行结束,但是还没释放资源的进程。而对于单CPU的系统来说,获得CPU使用权的进程状态就是执行态,进程执行结束就应该释放资源。

目录

一、结构体定义

二、上下文切换

三、优先级队列

四、进程操作

五、编译和执行


一、结构体定义

在 type.h中 定义进程的结构体:

为了尽量和实际操作系统中保持一致,要把栈 kstack 放在结构体的最后面,栈底到栈顶,就是从高地址到低地址,从kstack[SSIZE -1 ] 到 kstack [0] 。而saved_sp就是这个栈的栈顶指针。

//
// Created by Administrator on 2021/6/7.
//#ifndef PROCESSMANAGEMENT_TYPE_H
#define PROCESSMANAGEMENT_TYPE_H#define NPROC 9
#define SSIZE 1024
#define proc PROCenum ProcStatus{FREE=0,READY,SLEEP};typedef struct Process{struct  Process * next; //同优先级的下一个同状态进程int *saved_sp ;              //栈顶指针int pid;                //idint ppid;               //父进程int status;             //状态   Free|ready| etcint priority;           //优先级int event ;             //造成睡眠的事件idint exitCode ;          //进程退出值struct Process *child;     //first child PROC pointerstruct Process *slbling;   //兄弟节点struct Process *perent;    //父节点int kstack[SSIZE];      //栈空间}PROC;#endif //PROCESSMANAGEMENT_TYPE_H

二、上下文切换

上下文切换,指的是正在执行的进程因为某些原因需要让出CPU使用权,需要保留现有的状态,等到重新获得CPU使用权的时候,恢复刚刚暂停执行时的状态继续执行。scheduler 方法在后续中会讲到,它的功能是把当前执行的进程running弄到就绪队列中,再从就绪队列中搞一个进程来执行。

在tswitch.s 汇编文件中写入下述代码。其中

movl   running,%ebx    
          movl   %esp,4(%ebx)

这段代码把 running指针的值放入%ebx,而 4(%ebx)则是running地址再往高地址偏移4个字节,对应再程序中的变量是 Process 中的 *saved_sp变量。所以这两句代码就是为了 saved_sp= %esp

当running换成新进程后,再 Resume 代码块,先 %esp = saved_sp,然后再按顺序出栈,把之前的状态进行恢复。执行到ret时,弹出PC寄存器的代码地址继续执行。

          .globl  running,scheduler,tswitch
tswitch:
SAVE:                            # on entry: stack top = retPCpushl %eax             # save CPU registers on stackpushl %ebxpushl %ecxpushl %edxpushl %ebppushl %esipushl %edipushflmovl   running,%ebx    # ebx -> running PROCmovl   %esp,4(%ebx)    # running PROC.saved_sp = espFIND:    call   scheduler       # pick a new running PROCRESUME:     movl   running,%ebx    # ebx -> (new) running PROCmovl   4(%ebx),%esp    # esp =  (new) running PROC.saved_sppopfl                  # restore saved registers from stackpopl  %edipopl  %esipopl  %ebppopl  %edxpopl  %ecxpopl  %ebxpopl  %eaxret                    # return by retPC on top of stack # stack contents = |retPC|eax|ebx|ecx|edx|ebp|esi|edi|eflag|
#                    -1   -2  -3  -4  -5  -6  -7  -8   -9

三、优先级队列

队列采用链表形式进行组织,对进程列表按照优先级进行入队、出队、打印操作


#include "queue.h"/*** <p> 把进程指针P 放进优先级指针数组中* @param queue* @param p* @return*/
static int enqueue(PROC **queue ,PROC * p){PROC  *q = *queue;if (q==NULL || p->priority > q->priority){//如果队列为空或者P的优先级要比队列头来得高,那么直接放进队列头*queue = p;p->next = q;}else{//否则定位到对应的优先级序列while(q->next!=NULL && p->priority <= q->next->priority){q = q->next;}p->next = q->next;q->next = p;}
}static PROC* dequeue(PROC ** queue){PROC  *p= *queue;if(p!=NULL){*queue = (*queue)->next;}return p;
}static int printList (const char * name ,PROC * p){printf("%s =",name);while(p){printf("[%d %d ]->",p->pid,p->priority);p=p->next;}printf("NULL\n");return  0;
}

四、进程操作

1)定义执行、空闲、就绪、睡眠状态进程队列 ,本次示例最多有 NPROC=9 个进程

2)CPU使用权切换 scheduler,把一个正在执行的换进就绪队列中,再从就绪队列换出一个进程。

3)上下文切换 do_switch, 其中,tswitch的定义在 tswitch.s文件中。该方法实现,保存寄存器状态值,恢复一个就绪态的进程,并恢复该进程暂停之前的状态

4)创建进程 do_kfork ,从空闲队列中抽出一个进程并初始化信息,加入到就绪队列中。

在初始化过程中,kstack[SSIZE-1] 赋成和 body的函数地址,save_sp指针指向kstack[SSIZE -9]。意味着,如果在tswtich.s 执行 movl .save_sp ,%esp 后再pop  8个寄存器后,esp寄存器对应的内存单元就是kstack[SSIZE-1] 即body的函数地址,再ret一下,就会执行body函数。

5)进程退出 do_exit , 把进程重新加入到空闲队列中。

6)系统初始化  init ,假设在该系统中 proc [0]  即 P0 的进程优先级最低,在空闲列表中的进程都是P0进程的子进程 ,子进程的优先级都为1 ,P0进程的优先级为0。

7) main 函数:初始化进程P0,并创建一个子进程。调用tswitch 切换到子进程中,如果子进程都结束退出,那么P0才有机会重新获取CPU执行权。P0结束,程序结束

#include <stdio.h>
#include "type.h"int kfork(), kexit(), tswitch(), printList(), enqueue() ;PROC proc[NPROC], *running, *freeList, *readyQueue, *sleepList;int do_switch()
{printf("proc %d switching task\n", running->pid);tswitch();printf("proc %d resuming\n", running->pid);
}int do_kfork()
{int child = kfork();if (child < 0)printf("kfork failed\n");else{printf("proc %d kforked a child = %d\n", running->pid, child); printList("readyQueue", readyQueue);}return child;
}int kexit(){running->status = FREE;running->priority = 0;// ASSIGNMENT 3: add YOUR CODE to delete running PROC from parent's child listenqueue(&freeList, running);     // enter running into freeListprintList("freeList", freeList); // show freeListtswitch();
}int do_exit()
{if (running->pid==1){printf("P1 never dies\n");return -1;}kexit();    // journey of no return
}int body()
{int c, CR;printf("proc %d starts from body()\n", running->pid);while(1){printf("***************************************\n");printf("proc %d running: Parent = %d\n", running->pid, running->ppid);// ASSIGNMENT 3: add YOUR CODE to show child listprintf("input a char [f|s|q] : ");c = getchar(); CR=getchar(); switch(c){case 'f': do_kfork();     break;case 's': do_switch();    break;case 'q': do_exit();      break;}}
}/*******************************************************kfork() creates a child porc; returns child pid.When scheduled to run, child PROC resumes to body();
********************************************************/
int kfork()
{PROC *p;int  i;/*** get a proc from freeList for child proc: ***/p = dequeue(&freeList);if (!p){printf("no more proc\n");return(-1);}/* initialize the new proc and its stack */p->status = READY;p->priority = 1;         // for ALL PROCs except P0p->ppid = running->pid;//                    -1   -2  -3  -4  -5  -6  -7  -8   -9// kstack contains: |retPC|eax|ebx|ecx|edx|ebp|esi|edi|eflag|for (i=1; i<10; i++)p->kstack[SSIZE - i] = 0;p->kstack[SSIZE-1] = (int)body;p->saved_sp = &(p->kstack[SSIZE - 9]); /**************** ASSIGNMENT 3  ********************add YOUR code to implement the PROC tree as a BINARY treeenter_child(running, p);
****************************************************/enqueue(&readyQueue, p);return p->pid;
}int init()
{int i;for (i = 0; i < NPROC; i++){proc[i].pid = i; proc[i].status = FREE;proc[i].priority = 0;proc[i].next = (PROC *)&proc[(i+1)];}proc[NPROC-1].next = 0;freeList = &proc[0];        readyQueue = 0;sleepList = 0;// create P0 as the initial running processrunning = dequeue(&freeList);running->status = READY;running->priority = 0;  running->child = 0;  running->sibling = 0;  running->parent = running;printf("init complete: P0 running\n"); printList("freeList", freeList);
}/*************** main() ***************/
int main()
{printf("\nWelcome to 360 Multitasking System\n");init();kfork();  printf("P0: switch task\n");tswitch();printf("All dead. Happy ending\n");
}/*********** scheduler *************/
int scheduler()
{ printf("proc %d in scheduler()\n", running->pid);if (running->status == READY)enqueue(&readyQueue, running);printList("readyQueue", readyQueue);running = dequeue(&readyQueue);printf("next running = %d\n", running->pid);
}

五、编译和执行

编译上述文件:命令为

gcc -m32  t.c  tswtich.s queue.c

再执行 ./a.out 如下结果:

参考书本《Systems Programming in Unix/Linux》 或 译文《Unix/Linux 系统编程》

Linux C : 进程管理实验:创建进程、上下文切换相关推荐

  1. Linux入门之进程管理(4)之进程与文件

    Linux入门之进程管理(4)之进程与文件 前面使用进程相关命令管理工具都是根据进程编号或者进程名称及其其它属性信息来查看和处理相关进程的,但是在某些情况下,想要查看某个文件或者某个设备被哪些进程所使 ...

  2. linux文件权限管理实验心得,Linux+文件权限管理实验

    主机安全-- Linux文件权限管理实验 对于文件 /etc/passwd,该文件的属组(root)可读.不可写,不可执行 对于文件 /etc/shadow,该文件的属组(root)不可读.不可写,不 ...

  3. 操作系统之——进程管理:同步进程和进程互斥

    操作系统进程管理-同步和互斥 在看了操作系统关于进程管理中的同步互斥机制章节之后,甚是困惑,今天通过视频.网上博客资料学习之后,整理一下相关知识点. 进程管理 一.进程互斥 由于进程具有独立性和异步性 ...

  4. 实验1 进程管理实验-计算机操作系统

    在分析给定进程创建源代码基础上,结合可能使用的进程调度算法,完善PCB结构 编写程序实现进程撤销功能,并与进程创建程序构成一个进程管理程序,模拟实现进程的管理功能 进行动态的进程创建.撤销等测试. 按 ...

  5. 【Linux 内核】进程管理 ( 系统调用简介 | 进程相关系统调用源码 )

    文章目录 一.系统调用简介 二.进程相关系统调用源码 一.系统调用简介 在开发应用程序时 , 进行 " 进程创建 " , 调用的 fork() , vfork() , clone( ...

  6. 操作系统-进程管理实验(2)

    实验二  进程管理 一.目的 本课题实验的目的是,加深对进程概念及进程管理各个部分内容的理解:熟悉进程管理中主要数据结构的设计及进程调度算法,进程控制机构,同步机构,通信机构的实施. 二.题目 进程管 ...

  7. Linux进程管理(第二版) --进程管理命令

    进程管理命令 一.查看用户信息w 1. w显示信息的含义 TTY:说明用户登录的方式,ttyN:表示以本地终端登录;pts/N表示以远程终端登录 JCPU:以终端代号来区分,该终端所有相关的进程执行时 ...

  8. Linux系统内存管理实验报告,linux内存管理实验报告

    <linux内存管理实验报告>由会员分享,可在线阅读,更多相关<linux内存管理实验报告(13页珍藏版)>请在人人文库网上搜索. 1.操作系统实验报告院别:XXXXXX班级: ...

  9. 【知识强化】第二章 进程管理 2.1 进程与线程

    处理机管理相关的内容.认识一个很重要的概念叫做进程. 系统当中正在运行的程序怎么怎么地,怎么怎么地,偶尔也会提到进程这个术语."进程"和"程序"这两个概念是比较 ...

最新文章

  1. 用Windows Live Writer发布博客也可以不生成缩略图
  2. 计算机数学基础模拟试题,计算机数学基础(A)模拟试题.doc
  3. 0923html测试
  4. [Python] 索引序列函数:enumerate() / enumerate(sequence, start=0)
  5. 如何修改SecureCRT中的端口转发过滤器?
  6. VS 2005 下载地址
  7. 1100个商务企业宣传通用PPT模板免费下载网址
  8. Hello World CGAL 5.4入门
  9. 超简单!一部手机就能提取视频中的语音转换成文字
  10. 华硕天选3笔记本电脑WiFi功能消失
  11. git拉取最新的代码
  12. GEE实战3:利用GEE获取区域的长系列日均气温变化【逐日气温变化分析】
  13. 2023年春招热门笔试算法题(C++)
  14. 新概念英语第二册61-96课(转)
  15. 微信聊天记录删除后如何恢复?原来只要这样就可以了
  16. 【双端队列广搜/搜索+图论】AcWing 2019.拖拉机 USACO 2012 March Contest Silver Division
  17. Eyelink眼动仪与Psychopy连接
  18. Interpolator插值器
  19. python除法保留小数_python中的除法_python中除法_python 除法_python 除法保留小数
  20. DeepCTR:易用可扩展的深度学习点击率预测算法库

热门文章

  1. Centos7 Java8的安装
  2. Oracle计划任务JOB不自动执行的问题
  3. 集合论在图论中的应用的约束描述
  4. CLR自定义菜单项(ToolStripItem)
  5. 神经网络中的激活函数的比较
  6. Ubuntu 安装 QQ
  7. ThreadLocal基本使用和内存泄漏分析
  8. SpringBoot @Value、 @ConfigurationProperties 与 @EnableConfigurationProperties 使用
  9. reactjs组件实例的三大属性之props使用示例:在函数式组件中使用props
  10. Fedora 35安装 VMware Workstation 16.1.2并解决报错:efore you can run VMware several modules must be compiled