进程管理的模拟程序_实验一熟悉C语言的运行环境

进程管理的模拟程序_实验一熟悉C语言的运行环境利用C语言模拟实现操作系统中的进程管理

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

这星期开始上计算机操作系统的实验课,打算把每个实验的内容和思路记录一下

实验目的

1、 理解进程的概念,明确进程和程序的区别。

2、 理解并发执行的实质。

3、 掌握进程的创建、睡眠、撤销等进程控制方法。

实验内容与基本要求

用C,C++等语言编写程序,模拟实现创建新的进程;查看运行进程;换出某个进程;杀死进程等功能。

实验报告内容

1.进程、进程控制块等的基本原理

a.为了能使程序并发执行,并且可以对并发执行的程序加以描述和控制,引入了“进程”的概念。它是资源分配和独立运行的基本单位。

b.进程控制块(PCB)是操作系统为进程配置的一个专门的数据结构。系统利用PCB来描述进程的基本情况和活动过程,进而控制和管理进程。

进程PCB可以包含

/* |进程ID| |进程优先级| |进程大小(进程执行时间| |进程内容| |进程状态| |指针| */

2.进程过程图

img_1

以传统菜单的形式呈现功能。

1.创建新的进程 2.查看运行进程”

3.换出某个进程 4.杀死运行进程”

5.唤醒某个进程 6.退出程序 “

实现思路及功能分析

系统利用进程控制块(Process Control Block,PCB)来描述系统的基本情况和活动过程,要进行进程管理,实际上就是在操作进程的PCB。因此要求模拟进程管理,首先要模拟出PCB的结构,再实现它的创建、撤销等操作。

一般来说,进程拥有三种基本状态:就绪、执行、阻塞。在引入了挂起原语操作后,还会细分为活动就绪、静止就绪、活动阻塞、静止阻塞。在我的理解中,活动与静止的区别就是,活动时进程是在主存中的,而静止时进程已经被调到了辅存里。

在单处理机系统中,只有一个进程处于执行状态,而在多处理机系统中,能有多个进程处于执行状态。因此在这里我们不将执行状态与就绪状态特别区分开来,只设置两个链表,一个链表用于保存处于执行(或就绪)状态的进程,一个链表用于保存处于阻塞状态的进程。

当然,如果想模拟单处理机系统的话,也可以将处于就绪状态链表的第一个结点默认设置为执行状态,当有优先度更高的进程时,让它成为执行状态,插入链表头部,原有的第一个结点转为就绪状态即可。但是本实验中不涉及优先级调度的算法,所以就简化处理了。

同样,我们模拟内存的大小,例如理论上可以同时运行20个进程,那么将处于执行状态的进程转为阻塞状态时,可以看做把它转移到了辅存中。但是不区分活动阻塞、静止阻塞,只是简单地设置成运行进程个数的变化。

总的来说,我们这次试验的思路是

  • 设置两个单链表,一个用于存储运行的进程,一个用于存储阻塞状态的进程
  • 默认内存中可以存放最多20个进程,将处于运行队列的进程看作在内存中,阻塞状态不在内存中
  • 进程创建,则去申请内存空间,填写完进程信息后直接加入运行队列
  • 杀死进程,则将进程从运行队列中删除,并直接释放
  • 进程的换出与唤醒,就是让进程在运行队列与阻塞队列之间转换(进程自己的状态也发生改变)
  • 为了操作简便,额外写了几个辅助函数来使用

流程图

img_2

全部代码

工程图

img_2

ProcessControl.h

//
// ProcessControl.h
// ProcessControlTest
//
// Created by Apple on 2019/10/13.
// Copyright © 2019 Yao YongXin. All rights reserved.
//

#ifndef ProcessControl_h
#define ProcessControl_h

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

//最大内存的大小
#define MAX_SIZE 20

//线程状态:运行(就绪) 阻塞
enum process_type{ 
   
    process_type_running = 1000,
    process_type_block = -1000,
    process_type_ready = 500
};

//进程控制块结构体
typedef struct PCB_Type{ 
   
    //进程的id
    int pid;
    //进程的优先级
    int priority;
    //进程大小(执行时间)
    int size;
    //进程内容
    char content[20];
    //进程的状态 执行 阻塞
    int state;
    //下一个要执行的进程
    struct PCB_Type *next;
}PCB;

//创建新的进程
void create(PCB *running_list,PCB *block_list,int *size);
//查看运行进程
void show_running(PCB *running_list);
//换出某个进程
void change(PCB *running_list,PCB *block_list,int *size);
//杀死运行进程
void killed(PCB *running_list,int *size);
//唤醒某个进程
void wake_up(PCB *running_list,PCB *block_list,int *size);

//判断在运行(就绪)队列中是否存在有该pid值的进程 0->不存在 1->存在
int exist_in_running(PCB *running_list,int pid);
//判断在阻塞队列中是否存在有该pid值的进程 0->不存在 1->存在
int exist_in_block(PCB *block_list,int pid);
//通过pid寻找进程的位置(返回其前一个结点的地址
PCB *find(PCB *list,int pid);

#endif /* ProcessControl_h */

ProcessControl.c

//
// ProcessControl.c
// ProcessControlTest
//
// Created by Apple on 2019/10/13.
// Copyright © 2019 Yao YongXin. All rights reserved.
//

#include "ProcessControl.h"

//创建新的进程
void create(PCB *running_list,PCB *block_list,int *size){ 
   
    if (*size >= MAX_SIZE) { 
   
        //内存不足,无法创建
        printf("内存不足,无法创建新的进程\n");
        return;
    }
    //申请一个内存控制块的空间
    PCB *p = (PCB *)malloc(sizeof(PCB));
    assert(p != NULL);
    
    //设置该控制块的id值
    int pid;
    printf("请输入新进程的pid:\n");
    scanf("%d",&pid);
    
    //判断pid值是否重复
    if (exist_in_running(running_list, pid)) { 
   
        printf("该值已存在!\n");
        return;
    }
    if (exist_in_block(block_list, pid)) { 
   
        printf("该值已存在!\n");
        return;
    }
    //没重复,保存
    p->pid = pid;
    
    //设置该控制块的其他值
    printf("请输入新进程的优先级:\n");
    scanf("%d",&p->priority);
    printf("请输入新进程的大小:\n");
    scanf("%d",&p->size);
    printf("请输入新进程的内容:\n");
    scanf("%s",p->content);
    p->state = process_type_running;
    p->next = NULL;
    
    //放入就绪队列中
    PCB *s = running_list;
    while (s->next != NULL) { 
   
        s = s->next;
    }
    s->next = p;
    
    //进程数量+1
    *size = *size + 1;
}

//查看运行进程
void show_running(PCB *running_list){ 
   
    PCB *s = running_list->next;
    if (s == NULL) { 
   
        printf("没有正在运行的进程\n");
        return;
    }
    
    while (s != NULL) { 
   
        printf("进程id:%d\n",s->pid);
        printf("进程优先级:%d\n",s->priority);
        printf("进程大小:%d\n",s->size);
        printf("进程内容:%s\n",s->content);
        printf("___________\n");
        
        s = s->next;
    }
}

//换出某个进程
void change(PCB *running_list,PCB *block_list,int *size){ 
   
    if (*size == 0) { 
   
        printf("无可换出的进程\n");
        return;
    }
    
    int pid;
    printf("请输入需要换出进程的id:\n");
    scanf("%d",&pid);
    //查看该线程是否在就绪队列中
    if (exist_in_running(running_list, pid)) { 
   
        //存在,找到该线程的位置(返回的是前一个结点的地址
        PCB *s = find(running_list, pid);
        //修改线程状态
        s->next->state = process_type_block;
        
        //将该线程存入阻塞队列中
        //寻找插入位置
        PCB *p = block_list;
        while (p->next != NULL) { 
   
            p = p->next;
        }
        //插入
        p->next = s->next;
        
        //将该线程从就绪队列中移出
        s->next = s->next->next;
        
        //将该线程的next重置为空
        p->next->next = NULL;
        
        *size = *size - 1;
        printf("成功换出\n");
    }else{ 
   
        printf("该线程不存在或已处于阻塞状态\n");
    }
}

//杀死运行进程
void killed(PCB *running_list,int *size){ 
   
    if (*size == 0) { 
   
        printf("无可杀死的进程\n");
        return;
    }
    
    int pid;
    printf("请输入要杀死的进程id:\n");
    scanf("%d",&pid);
    //判断该进程是否存在
    if (exist_in_running(running_list, pid)) { 
   
        //存在,找到该线程的位置(返回的是前一个结点的地址
        PCB *s = find(running_list, pid);
        //保存该线程的地址,用于释放
        PCB *thisThread = s->next;
        //将该线程从就绪队列移出
        s->next = s->next->next;
        *size = *size - 1;
        
        //直接释放掉该线程
        free(thisThread);
        printf("成功杀死\n");
    }else{ 
   
        printf("该线程不存在或已处于阻塞状态\n");
    }
}

//唤醒某个进程
void wake_up(PCB *running_list,PCB *block_list,int *size){ 
   
    PCB *s = block_list;
    if (s->next == NULL) { 
   
        printf("没有可唤醒的线程\n");
        return;
    }
    
    int pid;
    printf("请输入要唤醒的进程id:\n");
    scanf("%d",&pid);
    //判断该进程是否存在
    if (exist_in_block(block_list, pid)) { 
   
        //存在,查找到该线程的位置(返回的是前一个结点的地址
        s = find(block_list, pid);
        //修改线程状态
        s->next->state = process_type_running;
        
        //将该线程存入就绪队列中
        //寻找插入位置(最后一位)
        PCB *p = running_list;
        while (p->next != NULL) { 
   
            p = p->next;
        }
        //插入
        p->next = s->next;
        
        //将该线程从阻塞队列中取出
        s->next = s->next->next;
        
        //将该线程的next值重置为null
        p->next->next = NULL;
        
        *size = *size + 1;
        printf("唤醒成功\n");
    }else{ 
   
        printf("该线程不存在\n");
    }
}

//判断在就绪队列中是否存在有该pid值的进程 0->不存在 1->存在
int exist_in_running(PCB *running_list,int pid){ 
   
    int result = 0;
    
    PCB *s = running_list->next;
    //遍历执行状态的链表
    while (s != NULL) { 
   
        if (s->pid == pid) { 
   
            //存在,直接返回
            result = 1;
            break;
        }
        s = s->next;
    }
    return result;
}
//判断在阻塞队列中是否存在有该pid值的进程 0->不存在 1->存在
int exist_in_block(PCB *block_list,int pid){ 
   
    int result = 0;
    
    //遍历阻塞状态的链表
    PCB *s = block_list->next;
    while (s != NULL) { 
   
        if (s->pid == pid) { 
   
            //存在,直接返回
            result = 1;
            break;
        }
        s = s->next;
    }
    
    return result;
}

//通过pid寻找进程的位置(返回其前一个结点的地址
PCB *find(PCB *list,int pid){ 
   
    PCB *s = list;
    
    while (s->next != NULL) { 
   
        if (s->next->pid == pid) { 
   
            return s;
        }
        s = s->next;
    }
    
    return NULL;
}

main.c

//
// main.c
// ProcessControlTest
//
// Created by Apple on 2019/10/13.
// Copyright © 2019 Yao YongXin. All rights reserved.
//

#include "ProcessControl.h"

void showLine(){ 
   
    printf("**************************\n");
}

int main(int argc, const char * argv[]) { 
   
    
    //运行(就绪)队列(头结点不储存信息)
    PCB *running_list = (PCB *)malloc(sizeof(PCB));
    running_list->next = NULL;
    
    //阻塞队列(头结点不储存信息)
    PCB *block_list = (PCB *)malloc(sizeof(PCB));
    block_list->next = NULL;
    
    //当前运行的线程数量
    int storage_number = 0;
    
    int choose = 1;
    while (choose) { 
   
        //展示菜单
        showLine();
        printf("* 进程演示系统 *\n");
        showLine();
        printf("1.创建新的进程 2.查看运行进程\n");
        printf("3.换出某个进程 4.杀死运行进程\n");
        printf("5.唤醒某个进程 6.退出程序 \n");
        showLine();
             
        printf("请选择(1~6):\n");
        scanf("%d",&choose);
             
        switch (choose) { 
   
            case 1:
                //创建新的进程
                create(running_list, block_list, &storage_number);
                break;
            case 2:
                //查看运行进程
                show_running(running_list);
                break;
            case 3:
                //换出某个进程
                change(running_list, block_list, &storage_number);
                break;
            case 4:
                //杀死运行进程
                killed(running_list, &storage_number);
                break;
            case 5:
                //唤醒某个进程
                wake_up(running_list, block_list, &storage_number);
                break;
            case 6:
                return 0;
            default:
                printf("没有这个选项!\n");
                break;
        }
             
    }
      
    return 0;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/195139.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • ASP NET MVC OutputCache

    ASP NET MVC OutputCacheASP.NETMVC提供了一个Filter来实现缓存,如果这个Attribute在方法上,当前方法的输出会被缓存起来,如果Attribute在Controller上,控制器中所有的方法的输出都会被缓存起来。这里的缓存可以设置过期时间,并且可以设置输出策略等等。1.OutputCache简单Demo[OutputCache(Duration=60)]publicActionRe

    2022年7月23日
    13
  • php webservice实例「建议收藏」

    php webservice实例「建议收藏」首先大家要简单了解了何谓webservice,接下来就做两个非常简单的例子,webservice还是逃不开server端与client端。我测试的环境为:apache2.2.11php5.2.10做这个测试之前,要确认你的php配置文件中已经将soap扩展打开,即extension=php_soap.dll;OK现在我们来体验webservice//server端serverSoap.php

    2022年7月21日
    12
  • Vue新手入门指南(易懂)

    Vue新手入门指南(易懂)Vue.js学习心得前言对于一名初入编程的新手来说,JavaScript的语法偏向复杂,选择Vue库可以说是一个较为不错的体验。在很多方面,Vue简化了JavaScrip语法,并且实现数据与视图的双向绑定,达到响应式页面的目的。1.Vue实例和模板语法<body> <divid=”app”> <p>{{message}}</p> </div><script> newVue({ el:’#app’

    2022年5月4日
    45
  • Android so文件浅析「建议收藏」

    Android so文件浅析「建议收藏」一.简述Android中的so文件是动态链接库,是二进制文件,即ELF文件。多用于NDK开发中。二.基础知识三.so文件格式解析so文件即ELF文件,是一个二进制文件,我们可以用UltraEdit打开查看。如下:上面有一处很明显看到,在so文件解析出来的头文件字段是ELF,也印证.so是一个ELF格式的问题。ELF文件…

    2026年1月24日
    4
  • 遗传算法优化bp神经网络matlab代码_神经网络进化算法

    遗传算法优化bp神经网络matlab代码_神经网络进化算法最近在学遗传算法优化BP神经网络,从新浪博客,Matlab中文论坛以及《MATLAB神经网络43个案例分析》里看了许多资料,存在着缺少test函数,以及函数名调用错误等问题。自编了test函数,调整后,供大家参考,(在Matlab2006a亲测可行)。参考文献:《MATLAB神经网络的43个案例分析》王小川,史峰,郁磊等,北京航空航天大学出版社。flyingnosky的sina博…

    2025年10月27日
    3
  • 数据库中的having语句_sql的having语句

    数据库中的having语句_sql的having语句SQL语句HAVING的用法HAVING语句通常与GROUPBY子句及聚集函数COUNT,AVG,SUM,MAX,MIN语句联合使用,用来过滤由GROUPBY语句返回的记录集,通常跟在GROUPBY后边作用相当于WHERE。where子句后边是指定行所对应的条件,并且不能含有聚集函数,而HAVING后边是指定组所对应的条件,可以含有聚合函数。HAVING语句的存在弥补了WHERE关键字不能与聚集函数联合使用的不足。我们可以这样理解:where筛选的是行(一个元组),而having筛选的是组(多

    2025年8月30日
    6

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号