linux 中断和进程 传递,操作系统课程设计linux :编制shell程序、进程软中断通信、内存的申请与释放,多进程求100000个浮点数的和...

操作系统课程设计,编制shell程序、进程软中断、内存的申请与释放,多进程大数运算

编制一个Shell程序

进程的软中断通信

内存的申请、使用与释放

多进程求100000个浮点数(精确小数点右4位)的和

本次实验在vmware 15pro 虚拟机ubuntu16.04 图形界面上完成。

本次实验建议用gedit编辑器完成,这个编辑器比较适合于linux新手,在gedit中可以使用ctrl+s 、ctrl+c、ctrl+v等快捷键。

1、 编制一个Shell程序,并让该程序在用户登录时自动执行,显示提示信息“Welcome!Have a nice day!”,并在命令提示符中包含系统名称、内核版本、当前目录、当前用户名等基本信息。

通过在 /etc/profile.d 文件夹中加入shell脚本。

首先,进入该目录,打开终端,输入以下代码创建一个 welcome.sh 文件。

gedit welcome.sh

输入以下的代码,保存即可。

#!/bin/bash

echo Welcome! Have a nice Day!

uname -s -r #输出系统名字和内核版本

pwd #输出当前目录

id -un #输出当前用户名

然后以命令行的方式启动linux,输入正确的账号密码即可看到结果,如下图。PS:图形界面启动,是看不到shell程序自启动的,必须从命令行界面启动。从ubuntu图形界面转换到命令行界面,按ctrl+F2。返回图形界面按ctrl+F7

55f0281d7f08111c861a1cafa1750005.png

2、 linux进程的软中断通信

编写一段程序实现进程的软中断通信,要求:

①使用系统调用fork()创建两个子进程,再用系统调用signal()让父进程捕捉键盘上来的中断信号(即按ctrl+c键);当捕捉到中断信号后,父进程用系统调用Kill()向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止:

Child Processll is Killed by Parent!

Child Processl2 is Killed by Parent!

父进程等待两个子进程终止后,输出如下的信息后终止。

Parent Process is Killed!

②在上面的程序中增加语句signal (SIGNAL, SIG-IGN) 和signal (SIGQUIT, SIG-IGN), 观察执行结果,并分析原因。

由于原题中的signal (SIGNAL, SIG-IGN)权限过高,已经被当下的linux的系统所弃用,在此将增加语句signal (SIGNAL, SIG-IGN)更改成增加语句signal(SIGINT,SIG_IGN)。

为防止篇幅过长,这里可以参考我的另一篇博客。linux进程的软中断通信

3、 操作函数进行内存的申请、使用与释放

利用c语言的malloc函数,为int类型的x指针申请一个int类型的内存空间,然后定义一个int类型的临时变量y并给y赋值100。接着,将y赋值给指针x。此时,通过输出x的值可以检验x是否申请到了内存,如果申请内存成功,则此时输出的x的值和y的值相同。内存的释放使用的是free函数,释放内存后,再次输出x,如果此时x的值为零,说明内存释放成功,因为在c语言中,当定义了一个整型变量而没有给它赋初值时,默认的值是0。

运行结果如下图

20c5c696e06dda671f505ed0c8d53295.png

源代码如下

#include

#include

int main(){

int *x=(int *)malloc(sizeof(int));//申请内存

int y=100;

*x=y;

printf("\nx申请到内存后:x的值为:%d\n",*x);

free(x);//释放内存

printf("\nx释放内存后:x的值为:%d\n",*x);

}

4、多进程求100000个浮点数(精确小数点右4位)的和

要求:

① 随机生成100000个浮点数,要求精确到小数点右4位(父进程);

② 创建4个子进程,分别求25000个浮点数之和;

③ 父进程完成100000个浮点数之和并打印结果;

④ 统计顺序计算的时间和多个进程采用多道程序设计完成计算的时间。

4.1计算顺序计算的时间

设计思想:建立一个c语言文件,在main函数的开头先进行初始化处理,如建立一个二维数组double a[4][25000],用来装随机数的数组,将题目要求的十万个浮点数分成四份,每份二万五千个浮点数;再建立一个一维数组double sum[4]={0.0}来装四个子进程的计算浮点数的和。用精确到微秒的结构struct timeval,以及tv_usec来记录顺序计算开始的时刻。通过两个for循环(其中一个for循环嵌套在另一个当中),利用rand()获取随机生成的十万个浮点数。然后创建四个子进程,每个子进程中先计算自己的那份二万五千个浮点数的和,然后写进通道中,然后在父进程中将通道中的计算和打印出来。最后,父进程将所有子进程的和加在一起,完成一个顺序计算,获取顺序计算结束的时刻,接着利用该时刻减去顺序计算开始的时刻,就获得了顺序计算的时间,单位是微秒。

运行结果如下:

7f52ea41df65b123040d4591f52c10fc.png

源代码如下

#include

#include

#include

#include

#include

static double allsum=0.0;

int main()

{

int i,j;

double a[4][25000];

double sum[4]={0.0};//装四个进程的计算和

double readBuf[4];

time_t start,end;//定义一个开始时间和结束时间

struct timeval js;//结构struct timeval 精确到微秒

pid_t pid;

int fp[4][2];//创建一个管道二维数组

srand((unsigned)time(NULL));

//随机生成100000个浮点数(父进程)

for(i=0;i<4;i++)

for(j=0;j<25000;j++)

a[i][j]=(double)rand()/(double)RAND_MAX;

gettimeofday(&js,NULL);

start=js.tv_usec;//记录开始的时刻

for(i=0;i<4;i++)

{

if(pipe(fp[i])<0)

{

printf("pipe error");//创建管道失败

exit(1);

}

pid=fork();

if(pid<0)

{

printf("fork error!");

exit(1);

}

else if(pid==0)

{

for(j=0;j<25000;j++)

sum[i]+=a[i][j];

write(fp[i][1],&sum[i],sizeof(double));

exit(1);

}

else

{

if(!read(fp[i][0],&readBuf[i],sizeof(double)))

{

exit(1);

}

printf("sum[%d]=%.4f\n",i,readBuf[i]);

}

}

for(i=0;i<4;i++)

allsum+=readBuf[i];

printf("totalsum=%.4f\n",allsum);

gettimeofday(&js,NULL);

end=js.tv_usec;//tv_usec为Epoch到创建struct timeval时的微秒数

printf("time=%d us\n",end-start);

return 0;

}

4.2统计多进程计算的时间

设计原理:在上述的基础上进行改进,同样也是创建四个子进程,每个子进程中先计算自己的那份二万五千个浮点数的和,在子进程开始计算和之前获取该时刻,即子进程运行开始的时刻,然后计算结束后,又获取子进程计算结束后的时刻,用两个时刻相减就获得了单个子进程完成运算所花费的时间(单位:微秒),最后,把计算结果写进通道中,然后在父进程中将通道中的计算和打印出来。

运行结果如下

d044795bcb66ebf79dde593ef0a9fa29.png

源代码如下

#include

#include

#include

#include

#include

static double allsum=0.0;

int main()

{

int i,j;

double a[4][25000];

double sum[4]={0.0};

double readBuf[4];

time_t pidstart,pidend;//定义一个开始时间和结束时间

struct timeval js;//结构struct timeval 精确到微妙

pid_t pid;

int fp[4][2];

srand((unsigned)time(NULL));

//随机生成100000个浮点数(父进程)

for(i=0;i<4;i++)

for(j=0;j<25000;j++)

a[i][j]=(double)rand()/(double)RAND_MAX;

for(i=0;i<4;i++)

{

if(pipe(fp[i])<0)

{

printf("pipe error");

exit(1);

}

pid=fork();

if(pid<0)

{

printf("fork error!");

exit(1);

}

else if(pid==0)

{

gettimeofday(&js,NULL);

pidstart=js.tv_usec;

for(j=0;j<25000;j++)

sum[i]+=a[i][j];

write(fp[i][1],&sum[i],sizeof(double));

gettimeofday(&js,NULL);

pidend=js.tv_usec;//tv_usec为Epoch到创建struct timeval时的微秒数

printf("sum[%d].time=%d us\n",i,pidend-pidstart);

exit(1);

}

else

{

if(!read(fp[i][0],&readBuf[i],sizeof(double)))

{

exit(1);

}

printf("sum[%d]=%.4f \n\n",i,readBuf[i]);

}

}

for(i=0;i<4;i++)

allsum+=readBuf[i];

printf("totalsum=%.4f\n",allsum);

return 0;

}

在这里运用了一个十分重要的技术即管道技术;本题涉及到父子进程间数据的传递,易知从父进程传递数据到子进程中是非常容易实现的,而难点在于如何将子进程中的数据正确地传递到父进程中,而管道技术就是实现该难点。首先,介绍一下管道的基本的概念。管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质:

其本质是一个伪文件(实为内核缓冲区)

由两个文件描述符引用,一个表示读端,一个表示写端。

规定数据从管道的写端流入管道,从读端流出。

管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。

首先,创建一个管道二维数组int fp[4][2],4代表四个子进程,2代表管道的写端和读端,fd[0]→r;fd[1]→w,就像0对应标准输入,1对应标准输出一样。向管道文件读写数据其实是在读写内核缓冲区。在子进程中计算完浮点数的和后,然后直接写入管道中,再由父进程从管道中读出该数据,打印出来。管道技术的图解如下。

9263c5f5507b47911727594eacaeac16.png

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值