山东大学操作系统实验三-进程调度算法实验

一、实验目的

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

二、前置知识:linux中的调度策略-policy

linux 系统中调度策略 policy )可以是以下 3 种:
SCHED_OTHER   默认的分时调度策略( 值等于 0)
SCHED_FIFO        先进先先出调度策略 ( 值等于 1)
SCHED_RR          时间片轮转调度策略( 值等于 2)
后两种专用于对响应时间有特殊要求的进程,会抢先于 SCHED_OTHER调度策略的进程而执行。具有 SCHED_FIFO 调度策略的进程只能被更高优先级的进程抢先。
具有 SCHED_RR 调度策略的进程必要时可以与同级进程共享时间片。
进程优先数 (prio) 由静态优先数和动态优先数两部分组成,值越小调度优先级越高 。
具有 SCHED_OTHER 策略的进程静态优先数总是 0
动态优先数与进程的执行状态有关,但可以使用 nice 命令或系统调用加大进程优先数使其优先级降低,或用系统调用 setpriority 分别按进程或进程组或用户号设置介于 -20 +20 之间的动态优先数。
与进程调度策略有关的系统调用函数原型都声明在以下文件中:
#include <sched.h>
#include <sys/time.h>
#include <sys/resource.h>
设置进程调度策略的系统调用语法为:
int sched_setscheduler(pid_t pid,int policy,const struct sched_param *sp);
pid       进程号
policy   以上说明的 3 种调度策略之一
sp        调度参数结构指针 , 调度参数结构主要存有调度优先数
        struct sched_param {
        ...
        int sched_priority;
        ...
        };
返回值: 执行成功后返回 0
获取进程调度策略的系统调用语法为
int sched_getscheduler(pid_t pid);

pid  进程号
返回值: 进程当前的调度策略

设置进程动态优先数的系统调用语法为:
int getpriority(int which,int who); 
which   设置的对象,可以是:
                                        进程 PRIO_PROCESS
                                        进程组 PRIO_PGRP
                                        用户 PRIO_USER
who       对应设置对象的进程号或组号或用户号
返回值 : 所有匹配进程中的最高优先数
设置进程动态优先数的系统调用语法为:
int setpriority(int which,int who,int prio);
which   设置的对象,可以是:
                                        进程 PRIO_PROCESS
                                        进程组 PRIO_PGRP
                                        用户 PRIO_USER
who       对应设置对象的进程号或组号或用户号
prio        要设置的进程优先数
返回值 : 所有匹配进程中的最高优先数

三、示例实验分析

该示例实验测试在 linux 系统中不同调度策略和不同优先数的调度效果。

1.pached.c 父进程创建3个子进程为他们设置不同的优先数的调度策略

#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)
 {
 //取进程优先数放在调度策略数据结构中
 //如果 argv[i+1] 非 NULL,则将其转换为整数。
 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; 
}

argv: 这是一个命令行参数数组,通常是从 main 函数的参数中传入的,main函数中的 argc 是参数的个数,argv 是参数值的数组。
atoi( ): atoi 是一个标准库函数,将字符串转换为整数。

2.makefile文件

srcs = psched.c 
objs = psched.o 
opts = -g -c 
all: psched 
psched: $(objs) 
gcc $(objs) -o psched 
psched.o: $(srcs) 
gcc $(opts) $(srcs) 
clean: 
rm psched *.o

3.生成可执行文件psched

$gmake
gcc -c psched.c
gcc psched.o -o psched

4. 运行 psched,指定 3 个子进程的优先数为 10, 5, -10;调度策略都是默认策略

$./psched 10 5 -10 0 0 0
child 10771 policy is 0
child 10772 policy is 0 30 
child 10773 policy is 0
Child PID = 10773 priority = -10
Child PID = 10772 priority = 5
Child PID = 10771 priority = 10
......
Child PID = 10773 priority = -10
Child PID = 10772 priority = 5
Child PID = 10771 priority = 10
可以看出在相同的调度策略下优先数小的进程先得到了执行。

5. 再次运行 psched,指定 3 个子进程的优先数为 10, 5, 18;调度策略分别是 0,0,1

./psched 10 5 18 0 0 1
My child 11306 policy is 0
My child 11307 policy is 0
My child 11308 policy is 1
Child PID = 11308 priority = 18
Child PID = 11307 priority = 5
Child PID = 11306 priority = 10
Child PID = 11308 priority = 18
Child PID = 11307 priority = 5
Child PID = 11306 priority = 10
可以看出虽然 11308 进程其优先数最大,但由于其调度策略为先进先出,因此
总是首先得到调度。

四、独立实验分析

设有两个并发执行的父子进程,不断循环输出各自进程号、优先数和调度策略。
进程初始调度策略均为系统默认策略和默认优先级。
当某个进程收到 SIGINT信号时会自动将其优先数加 1 ,收到 SIGCSTP 信号时会自动将其优先数减 1 。请编程实现以上功能。

1.sched.c

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sched.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>

// 信号处理函数
void adjust_priority(int sig)
{
    int which = PRIO_PROCESS;
    int who = 0; // 0表示当前进程
    int prio = getpriority(which, who);

    if (sig == SIGINT)
    {
        prio++;
    }
    else if (sig == SIGTSTP)
    {
        prio--;
    }

    setpriority(which, who, prio);
}

int main()
{
    pid_t pid;
    struct sched_param sp;

    // 设置信号处理函数
    signal(SIGINT, adjust_priority);
    signal(SIGTSTP, adjust_priority);

    pid = fork();

    if (pid < 0)
    {
        perror("fork failed");
        exit(EXIT_FAILURE);
    }
    else if (pid == 0)
    {
        // 子进程
        while (1)
        {
            int policy = sched_getscheduler(0);
            int prio = getpriority(PRIO_PROCESS, 0);
            printf("Child PID = %d, Priority = %d, Policy = %d\n", getpid(), prio, policy);
            sleep(1);
        }
    }
    else
    {
        // 父进程
        while (1)
        {
            int policy = sched_getscheduler(0);
            int prio = getpriority(PRIO_PROCESS, 0);
            printf("Parent PID = %d, Priority = %d, Policy = %d\n", getpid(), prio, policy);
            sleep(1);
        }
    }

    return 0;
}

signa函数

void (*signal(int sig, void (*func)(int)))(int);

signa函数将指定信号(SIGINTSIGTSTP)与处理函数 adjust_priority 关联起来。当进程收到 SIGINTSIGTSTP 信号时,操作系统会调用 adjust_priority 函数,并将相应的信号编号作为参数传递给它。

2.makefile

srcs = priority_adjust.c
objs = priority_adjust.o
opts = -g -c
all: priority_adjust
priority_adjust: $(objs)
	gcc $(objs) -o priority_adjust
priority_adjust.o: $(srcs)
	gcc $(opts) $(srcs)
clean:
	rm priority_adjust *.o

  • 23
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值