操作系统实战(三)(linux+C语言实现)

实验目的

加深对进程调度概念的理解,体验进程调度机制的功能,了解Linux系统中进程调度策略的使用方法。 练习进程调度算法的编程和调试技术。

实验说明

1.在linux系统中调度策略分为3种

  • SCHED_OTHER:默认的分时调度策略,值为0
  • SCHED_FIFO:先进先出调度,值为1
  • SCHED_RR:轮转法调度,值为2

理解关键点:

  • 不同调度策略之间本身的优先级不同,FIFO调度策略优先级最高,其次是轮转法调度法,最后是默认分时调度策略(FIFO的所有程序相比于分时程序优先级更高)
  • 分时调度策略的优先级指的是动态优先级。动态优先级=nice值+进程运行时间值来决定的。对于FIFO、RR来说只是决定nice值的方式不一样

2.设置进程调度策略的系统调用语法

int sched_setscheduler(pid_t pid,int policy,const struct sched_param *sp);
  • pid:进程号
  • policy:三种调度策略之一
  • sp:调度参数结构指针,里面有调度优先数

理解关键点:

  • 设置进程的调度策略时,输入的参数肯定有:进程标识pid、调度策略policy。同时考虑到确定进程调度策略后要马上根据进程优先级来确定进程实际的执行次序,所以在设置进程调度策略时需要传递进程优先级
  • sched_setscheduler函数在sched.h头文件当中
  • 执行成功返回0

3.获取进程调度策略的系统调用语法

int sched_getscheduler(pid_t pid);
  • pid 进程号
  • 返回值: 进程当前的调度策略对应的数值

4.获取进程动态优先数的系统调用语法

int getpriority(int which,int who);

理解关键点: 

1、which代表设置的对象是什么类型的(进程、进程组、用户)

2、which的值可以是:

  • 进程 PRIO_PROCESS
  • 进程组 PRIO_PGRP
  • 用户 PRIO_USER

3、who的值是:设置对象类型下的标号(进程号或组号或用户号)

4、返回值:所有匹配进程中的最高优先级(本次实验是查找进程pid,所以结果只有一个)

5.设置进程动态优先数的系统调用语法

int setpriority(int which,int who,int prio);

理解关键点:

1、which代表设置的对象,which的值可以是

  • 进程 PRIO_PROCESS
  • 进程组 PRIO_PGRP
  • 用户 PRIO_USER

2、who表示对应查找对象集合中的具体实例 

3、prio设置的是要设置的进程优先级

4、返回值:所有匹配进程中的最高优先级

实例程序 

#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <sys/time.h>
#include <sys/resource.h>
int main(int argc, char *argv[])
{
    int i,j,status;
    int pid[3]; //存放进程号
    struct sched_param p[3]; //设置调度策略时使用的数据结构
    for(i=0; i<3;i++)
    {
        //循环创建3 个子进程
        if((pid[i]=fork()) >0)
        {
            //取进程优先数放在调度策略数据结构中
            p[i].sched_priority = (argv[i+1] != NULL) ? atoi(argv[i+1]):10;
            //父进程设置子进程的调度策略.如果命令行第4,5,6 参数指定了3个策略值则按指定的数设置,否则都为默认策略
            sched_setscheduler(pid[i],(argv[i+4] != NULL) ? atoi(argv[i+4]) : SCHED_OTHER,&p[i]);
            //父进程设置子进程的优先数,如果命令行第1,2,3 参数指定了3个优先数则按指定的数设置,否则都为10
            setpriority(PRIO_PROCESS,pid[i],(argv[i+1] != NULL) ? atoi(argv[i+1]):10);
        }
        //各子进程循环报告其优先数和调度策略
        else
        {
            sleep(1);
            //每隔1 妙报告一次进程号和优先级
            for(i=0; i<10; i++)
            {
                printf("Child PID = %d priority = %d\n",getpid(),getpriority(PRIO_PROCESS,0));
                sleep(1);
            }
            exit( EXIT_SUCCESS);
        }
    }
    //父进程报告子进程调度策略后先行退出
    printf("My child %d policy is %d\n",pid[0],sched_getscheduler(pid[0]));
    printf("My child %d policy is %d\n",pid[1],sched_getscheduler(pid[1]));
    printf("My child %d policy is %d\n",pid[2],sched_getscheduler(pid[2]));
    return EXIT_SUCCESS;
}

运行结果 

结果解释 

1、父进程先运行结束:父进程并未用wait等待子进程。同时对子进程使用sleep函数来休眠,所以父进程一定先运行结束并汇报出子进程的调度策略

2、优先数小的进程先执行:按照正常逻辑推理应该是优先数小的进程先执行,但是对于现在的多核CPU来说不同优先级的三个子进程仍然几乎可以说是在并行的(不是并发),所以实际效果是三进程顺序不太固定。但是可以看到优先级为18的进程不可能是第一个被调度的,说明优先级仍然在影响对CPU资源的占用

3、进程调度策略的修改:由于没有开sudo管理员权限,所以不允许对进程的调度策略进行修改

本次实验代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <sched.h>
#include <sys/time.h>
#include <sys/resource.h>
static int priority1=0;
static int priority2=0;
//加信号,只对子进程
void add(int sig)
{
    priority2++;
}
//减信号,只对子进程
void minus(int sig)
{
    priority2--;
}
int main(int argc, char *argv[])
{
    //绑定信号
    signal(SIGINT,add);
    signal(SIGTSTP,minus);
    //定义数组存储父子进程的pid值
    int pid[2];

    //父进程运行
    if((pid[1]=fork())>0)
    {
        pid[0] = getpid();
        struct sched_param p[2];
        //得到argv参数
        int priority1=atoi(argv[1]);
        int priority2=atoi(argv[2]);

        //父进程初始化父子进程优先级以及调度策略
        for(int i=0; i<2;i++){
            //取进程优先数放在调度策略数据结构中
            p[i].sched_priority = (argv[i+1] != NULL) ? atoi(argv[i+1]):10;
            //父进程设置自己和子进程的调度策略
            sched_setscheduler(pid[i],(argv[i+3] != NULL) ? atoi(argv[i+3]):SCHED_OTHER,&p[i]);
            //父进程设置自己和子进程的优先数
            setpriority(PRIO_PROCESS,pid[i],(argv[i+1] != NULL) ? atoi(argv[i+1]):10);
        }
        //父进程循环调整优先级
        int parentPid=getpid();
        while(1)
        {
            //输出进程号
            printf("parent pid = %d\n",parentPid);
            //输出优先级
            printf("parent process priority = %d\n",getpriority(PRIO_PROCESS,parentPid));
            //输出调度策略
            printf("parent process scheduler = %d\n",sched_getscheduler(parentPid));
            //设置进程的优先级
            setpriority(PRIO_PROCESS,parentPid,priority1);
            sleep(5);
        }
    }
    else
    {
        int childPid=getpid();
        while(1)
        {
            //输出进程号
            printf("child pid = %d\n",childPid);
            //输出当前运行进程的优先级(也就是子进程的优先级)
            printf("child process priority = %d\n",getpriority(PRIO_PROCESS,0));
            //输出调度策略
            printf("child process scheduler = %d\n",sched_getscheduler(childPid));
            //设置进程的优先级
            setpriority(PRIO_PROCESS,childPid,priority2);
            sleep(5);
        }
    }
}

运行结果

 

结果分析 

1、一开始设定父进程优先级为6,子进程为4。打入一个中断后,父子进程中便会是子进程先运行。(中断会让所有进程都去执行信号处理函数,然后再统一开始顺序执行进程)

2、后续利用自定义add方法能够让子进程的优先级变为8,此时大部分情况下,会先调度父进程后调度子进程(如何错乱了利用中断信号可以恢复正确的顺序)

3、有时候进程调度的顺序不是完全按照设定优先级进行的,为了防止部分进程恶意抢占所有资源,并且其他的进程随着时间也会增加静态优先级,从而获得更高的优先级

 makefile文件

# DEPEND   代替  依赖文件
# CC       代替  gcc
# CFLAGS   代替  编译命令
# PARA     代替  参数
# OBJS     代替 目标文件

DEPEND=expr_3.c
OBJS=expr_3
CC=gcc
CFLAGS=-o
PARA=6 4 0 0

expr_3:$(DEPEND)
	$(CC) $(DEPEND) -o $(OBJS)
	
run:$(OBJS)
	./$(OBJS) $(PARA)

clean:
	rm *.o $(OBJS) -rf

总结

本文到这里就结束啦~~

本篇文章重点在于利用linux系统的完成操作系统的实验,巩固课堂知识

本篇文章的撰写+实验代码调试运行+知识点细致化学习,共花了本人3h左右的时间

如果仍有不够希望大家多多包涵~~如果觉得对你有帮助,辛苦友友点个赞哦~

知识来源:山东大学操作系统实验三、山东大学《操作系统原理实用实验教程》张鸿烈老师编著

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/612019.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

通俗的理解网关的概念的用途(四):什么是网关设备?(网络层面)

任何一台Windows XP操作系统之后的个人电脑、Linux操作系统电脑都可以简单的设置&#xff0c;就可以成为一台具备“网关”性质的设备&#xff0c;因为它们都直接内置了其中的实现程序。MacOS有没有就不知道&#xff0c;因为没用过。 简单的理解&#xff0c;就是运行了具备第二…

使用nmcli命令在Linux系统上配置各种网络(有线、无线、vlan、vxlan、路由、网桥等)

前言&#xff1a;原文在我的博客网站中&#xff0c;持续更新数通、系统方面的知识&#xff0c;欢迎来访&#xff01; 使用nmcli命令在Linux系统上配置各种网络&#xff08;有线、无线、vlan、vxlan、路由、网桥等&#xff09;https://myweb.myskillstree.cn/123.html 你是否会…

使用GitLab自带的CI/CD功能在远程服务器部署项目(三)

前置内容&#xff1a; 通过Docker Compose部署GitLab和GitLab Runner&#xff08;一&#xff09; 使用GitLab自带的CI/CD功能在本地部署项目&#xff08;二&#xff09; 目录 一、在GitLab服务器上生成私钥与公钥 二、将公钥拷贝到应用服务器上 三、将私钥给到Docker Exec…

Windows系统下通过nginx配置多项目

文章目录 前言大概思路实际操作记录&#xff1a;查看nginx 错误日志问下AI注意点&#xff1a; 当访问域名根路径时&#xff0c;重定向到/pc总结 前言 在windows电脑启动一个nginx 测试配置多前端项目&#xff0c;一个pc端&#xff08;vue3tsvite &#xff0c;history路由&…

Vue3专栏项目 -- 二、自定义From组件(下)

需求分析&#xff1a; 现在我们还需要一个整体的表单在单击某个按钮的时候可以循环的验证每个input的值&#xff0c;最后我们还需要有一个事件可以得到最后验证的结果&#xff0c;从而进行下一步的操作 如下&#xff0c;我们应该有一个form表单包裹着全部的input表单&#xf…

【C语言】整数和浮点数在内存中的存储

大家可能在学习的时候会经常疑惑数据在内存中是怎样存储的&#xff0c;今天用一篇博客给你讲清楚&#xff01;&#xff01;&#xff01;从此不再疑惑&#xff01;&#xff01;&#xff01; 文章目录 1. 整数在内存中的存储2. 大小端字节序和字节序判断2.1 什么是大小端2.2 为什…

[VulnHub靶机渗透] Hackademic: RTB1

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

day2_greedyIntervalsLRU/LFU

二、贪心算法之区间调度问题 0.计算一个区间集合中无重复的区间的最大数量(模板) public int intervalSchedule(int[][] intvs) {if (intvs.length 0) return 0;// 按 end 升序排序Arrays.sort(intvs, (a, b) -> Integer.compare(a[1], b[1]));// 至少有一个区间不相交in…

Baidu Comate 编程插件:提升开发效率的利器

文章目录 引言简介目的 Baidu Comate插件概述定义与功能市场现状竞品分析 安装与配置VsCode 安装&#xff1a;注意事项 版本选择 核心特性详解功能介绍代码生成实时续写错误纠正 使用体验体验地址 引言 简介 基于文心大模型&#xff0c;结合百度积累多年的编程现场大数据和外…

专业做护眼灯的有哪些品牌?几款专业儿童卧室灯品牌分享

在当今时代&#xff0c;我们观察到一个不容忽视的现象&#xff1a;孩子们的视力问题日益增多&#xff0c;这无疑向众多家长发出了警示。它提醒着我们&#xff0c;除了追求学术成就之外&#xff0c;孩子们的视觉健康同样重要&#xff0c;不容忽视。因此&#xff0c;选择一款适合…

leetcode刷题:对称二叉树

题目&#xff1a; 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true 示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false 提示&#xf…

以导航产品为核心,东软想为车企扫除出海障碍

得益于新能源汽车领域多年的布局&#xff0c;以及在汽车智能化方面的先发优势&#xff0c;近年来&#xff0c;中国汽车品牌在质与量上都得到了极大提升&#xff0c;并带来强大的竞争力。 据海关总署公布的数据&#xff0c;过去三年&#xff0c;中国汽车出口规模连续突破式发展…

LeetCode算法题:7. 整数反转

给你一个 32 位的有符号整数 x &#xff0c;返回将 x 中的数字部分反转后的结果。 如果反转后整数超过 32 位的有符号整数的范围 [−2^31, 2^31 − 1] &#xff0c;就返回 0。 假设环境不允许存储 64 位整数&#xff08;有符号或无符号&#xff09;。 示例 1&#xff1a; 输…

会赚钱的人都在做这件事:你了解吗?

在我们日常生活的点滴中&#xff0c;以及在各种场合的交互中&#xff0c;利他思维始终扮演着不可或缺的角色。当我们追求合作与共赢时&#xff0c;单方面的自我立场显然是不够的&#xff0c;真正的关键在于换位思考&#xff0c;寻找并满足对方的需求。 互利互赢的核心理念正是利…

【挑战30天首通《谷粒商城》】-【第一天】【10 番外篇】 解决docker 仓库无法访问 + MobaXterm连接VirtualBox虚拟机

文章目录 课程介绍 1、解决docker 仓库无法访问 2、 MobaXterm连接VirtualBox虚拟机 Stage 1&#xff1a;下载MobaXterm选择适合你的版本 Stage 2&#xff1a;vagrant ssh 连接&#xff0c;开启ssh访问 Stage 2-1&#xff1a;su获取root账号权限,输入密码&#xff08;默认vagra…

纯血鸿蒙APP实战开发——阅读翻页方式案例

介绍 本示例展示手机阅读时左右翻页&#xff0c;上下翻页&#xff0c;覆盖翻页的功能。 效果图预览 使用说明 进入模块即是左右翻页模式。点击屏幕中间区域弹出上下菜单。点击设置按钮&#xff0c;弹出翻页方式切换按钮&#xff0c;点击可切换翻页方式。左右翻页方式可点击翻…

【软件测试】3.开发模型

目录 1.常见的开发模型 1.1瀑布模型 1.2螺旋模型 1.3增量模型和迭代模型 1.4敏捷模型 1.4.1特点&#xff1a; 1.5Scrum模型&#xff08;三个角色和五个重要会议&#xff09; 1.5.1三个角色&#xff1a; 1.5.2Scrum工作流程&#xff08;五个会议&#xff09; 1.6测试模…

如何选择适合自己网站的SSL证书提供商?

在互联网技术飞速发展的今天&#xff0c;确保数据安全已成为网站运营的基石。HTTPS证书作为一项重要的安全认证协议&#xff0c;对于保护数据传输的安全性至关重要。本文将为您提供一份详尽的指南&#xff0c;帮助您了解如何申请和部署HTTPS证书。 一、选择SSL证书提供商 首先…

JUC下的CompletableFuture详解

详细介绍 CompletableFuture是Java 8引入的一个实现Future接口的类&#xff0c;它代表一个异步计算的结果。与传统的Future相比&#xff0c;CompletableFuture提供了更丰富的功能&#xff0c;比如链式调用、组合异步操作、转换结果、异常处理等&#xff0c;极大地增强了Java在…