草庐IT

操作系统 进程控制 实验(C语言)

王回甘 2023-03-28 原文

进程控制

基本要求

  模拟操作系统内核对进程的控制和管理:包括进程的创建和撤销、进程状态的切换和简单的内存空间管理。

实验提示

  1、 定义管理每个进程的数据结构PCB:包含进程名称、队列指针、分配的物理内存区域(基址和长度)。每创建一个进程时,需要为其创建PCB并分配空闲内存空间,对PCB进行初始化,并加入就绪队列。(斜体为可选)

可参考如下数据结构(动态形式):

struct PCB{

char name[8];

struct PCB *next;

...

};

struct PCB *ready,*blocked,*running;

创建进程时申请空白PCB:

struct PCB *p=(struct PCB *)malloc(sizeof(struct PCB));

并把新建进程的PCB添加到就绪队列末尾:

add(ready,p);

其中,ready为就绪队列头节点,并在开始处分配了空间;add函数是链表中添加节点函数,代码参考如下:

 

void add(struct PCB *head, struct PCB *process){

   struct PCB *tmp=head;

   while(tmp->next!=NULL)

       tmp=tmp->next;

   tmp->next=process;

   process->next=NULL;

}

 

2、 模拟触发进程状态转换的事件:采用键盘控制方法来模拟触发进程状态切换的事件(例如输入1代表创建新进程、2执行进程时间片到、3阻塞执行进程、4唤醒第一个阻塞进程、5终止执行进程),实现对应的控制程序。

3、 根据当前发生的事件对进程的状态进行切换,并显示出当前系统中的执行队列、就绪队列和阻塞队列。

4、 *(选做)完成可变分区的分配与回收,创建进程的同时申请一块连续的内存空间,在PCB中设置好基址和长度,结束进程时回收分配的内存空间。分配可采用首次适应、最佳适应或最差适应算法,碎片大小为2Kb,最后回收所有进程的空间,对空间分区的合并。可以查看进程所占的空间和系统空闲空间。

可以用一个链表(如图1-1所示)来维护已分配的和空闲的内存段,其中一个段或者包含一个进程,或者是两个进程之间的空闲段。 在图1-1中,链表的每一项包含四个值域。第一个值域表示内存段是空闲或占用(例如,空闲段用H表示,进程占用的段用P表示);第二个值域表示内存段的起始位置,第三个值域表示内存段的长度;第四个值域为指向链表下一项的指针。该链表按照内存段的起始地址进行从小到大排序。这样排序的好处是方便内存空间的回收。一个要终止的进程一般会有两个邻居(除了在内存顶端和内存底端的进程)。邻居可能是进程也可能是空闲段。根据两个邻居的不同类型,可以分为四种回收情况(如图1-2所示)。在图1-2(a)中,对链表的更新只需要将P置为H;在图1-2(b)和(c)中,需要将P置为H,并将该项与另外一个相邻的空闲段的项合并为一项;在图1-2(d)中,需要将该项和两个邻居合并为一项。考虑到合并空闲段需要查看邻居,因此用双向链表会比单向链表更加方便。

 

 

 

1-1. (a) 内存空间的示例,有5个进程和3个空闲段,阴影部分表示空闲段。

(b) 管理内存空间的链表

 

 

 

1-2. 对终止的进程X的四种内存回收情况(阴影代表空闲区)

实验代码

 

#include<iostream>
#include<stdlib.h>
#include<string.h>
using namespace std;

struct PCB{
    char name[8];
    struct PCB *next;
};

struct PCB *ready,*blocked,*running;
struct PCB *p=(struct PCB *)malloc(sizeof(struct PCB));

//插入队列 
void add(struct PCB *head,struct PCB *process){
    struct PCB *tmp=head;
    while(tmp->next!=NULL)
        tmp=tmp->next;
    tmp->next=process;
    process->next=NULL;
}

//出队列 
struct PCB *movefirst(struct PCB *head){ 
    struct PCB *tmp=head->next;
    if(tmp!=NULL)
    {
        head->next=tmp->next;
        tmp->next=NULL;
    }
    return tmp;
};

//创建进程 
void creat()
{
    struct PCB *tmp;
    char name[10];
    cout<<"输入进程名字:";
    cin>>name;
    tmp=(struct PCB*)malloc(sizeof(struct PCB));
    strcpy(tmp->name,name);  //字符串复制函数 
    tmp->next=NULL;
    add(ready,tmp);
    if(running==NULL)   //如果当前没有正在执行的进程就将新创建的进程运行 
        running=movefirst(ready);
}

//时间片到 
void timeout(){
    if(ready->next==NULL)          //  容错处理
        cout<<"\t\t就绪队列为空!"<<endl;
    if(running!=NULL)
    {
        add(ready,running);
        running=movefirst(ready);
    }
    else
        running=movefirst(ready);
}

//阻塞进程 
void block(){
    if(running!=NULL)
    {
        add(blocked,running);
        running=movefirst(ready);
    }
    else
        cout<<"\t\t没有运行的进程,无法阻塞!"<<endl;
}


//唤醒进程
void wakeup(){
    if (blocked->next == NULL){
        printf("阻塞态已为空!!!\n");
    }
    else{
        struct PCB *T = (struct PCB*)malloc(sizeof(struct PCB));
        T = movefirst(blocked);
        add(ready,T);
        if (running == NULL){
            running =movefirst(ready);
        }
    }
}


//终止进程 
void stop(){
    if(running!=NULL)
    {
        free(running);
        running=movefirst(ready);
    }
    else
        cout<<"\t\t没有运行的进程"<<endl;
}

//展示 
void show()
{
    struct PCB *tmp;
    cout<<endl; 
    cout<<"执行队列:";
    if(running!=NULL)
        cout<<" "<<running->name;
    cout<<endl;
    cout<<"就绪队列:";
    tmp=ready->next;
    while(tmp!=NULL){
        cout<<" "<<tmp->name;
        tmp=tmp->next;
    }
    cout<<endl;
    cout<<"阻塞队列:";
    tmp=blocked->next;
    while(tmp!=NULL){
        cout<<" "<<tmp->name;
        tmp=tmp->next;
    }
    cout<<endl;
    cout<<endl;
}

//菜单 
void menu()
{
    cout<<"\t\t--------------------"<<endl;
    cout<<"\t\t1.创建进程"<<endl;
    cout<<"\t\t2.时间片到"<<endl;
    cout<<"\t\t3.阻塞进程"<<endl;
    cout<<"\t\t4.唤醒进程"<<endl;;
    cout<<"\t\t5.终止进程"<<endl;
    cout<<"\t\t6.退出程序"<<endl;
    cout<<"\t\t--------------------"<<endl;
}


main()
{
    ready=(struct PCB*)malloc(sizeof(struct PCB));
    ready->next=NULL;
    blocked=(struct PCB*)malloc(sizeof(struct PCB));
    blocked->next=NULL;
    int c;
    while(1)
    {
        menu();
        cout<<"输入功能:";
        cin>>c;
        switch(c)
        {
            case 1:
                creat();
                break;
            case 2:
                timeout();
                break;
            case 3:
                block();
                break;
            case 4:
                wakeup();
                break;
            case 5:
                stop();
                break;
            case 6:
                exit(0);
            default:
                cout<<"没有这个选项,请重新输入"<<endl;
        }
        show();
    }
}

 

有关操作系统 进程控制 实验(C语言)的更多相关文章

  1. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  2. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  3. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  4. Ruby Readline 在向上箭头上使控制台崩溃 - 2

    当我在Rails控制台中按向上或向左箭头时,出现此错误:irb(main):001:0>/Users/me/.rvm/gems/ruby-2.0.0-p247/gems/rb-readline-0.4.2/lib/rbreadline.rb:4269:in`blockin_rl_dispatch_subseq':invalidbytesequenceinUTF-8(ArgumentError)我使用rvm来管理我的ruby​​安装。我正在使用=>ruby-2.0.0-p247[x86_64]我使用bundle来管理我的gem,并且我有rb-readline(0.4.2)(人们推荐的最少

  5. ruby-on-rails - 带 Spring 锁的 Rails 4 控制台 - 2

    我正在使用Ruby2.1.1和Rails4.1.0.rc1。当执行railsc时,它被锁定了。使用Ctrl-C停止,我得到以下错误日志:~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`gets':Interruptfrom~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`verify_server_version'from~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.

  6. ruby-on-rails - openshift 上的 rails 控制台 - 2

    我将我的Rails应用程序部署到OpenShift,它运行良好,但我无法在生产服务器上运行“Rails控制台”。它给了我这个错误。我该如何解决这个问题?我尝试更新ruby​​gems,但它也给出了权限被拒绝的错误,我也无法做到。railsc错误:Warning:You'reusingRubygems1.8.24withSpring.UpgradetoatleastRubygems2.1.0andrun`gempristine--all`forbetterstartupperformance./opt/rh/ruby193/root/usr/share/rubygems/rubygems

  7. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  8. 电脑0x0000001A蓝屏错误怎么U盘重装系统教学 - 2

      电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。  准备工作:  1、U盘一个(尽量使用8G以上的U盘)。  2、一台正常联网可使用的电脑。  3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。  4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。  U盘启动盘制作步骤:  注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注

  9. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  10. Unity 热更新技术 | (三) Lua语言基本介绍及下载安装 - 2

    ?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------

随机推荐