本次实验在vmware 15pro 虚拟机ubuntu16.04 图形界面上完成。
本次实验建议用gedit编辑器完成,这个编辑器比较适合于linux新手,在gedit中可以使用ctrl+s 、ctrl+c、ctrl+v等快捷键。
通过在 /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
编写一段程序实现进程的软中断通信,要求:
①使用系统调用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进程的软中断通信
利用c语言的malloc函数,为int类型的x指针申请一个int类型的内存空间,然后定义一个int类型的临时变量y并给y赋值100。接着,将y赋值给指针x。此时,通过输出x的值可以检验x是否申请到了内存,如果申请内存成功,则此时输出的x的值和y的值相同。内存的释放使用的是free函数,释放内存后,再次输出x,如果此时x的值为零,说明内存释放成功,因为在c语言中,当定义了一个整型变量而没有给它赋初值时,默认的值是0。
运行结果如下图
源代码如下
#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);
}
要求:
① 随机生成100000个浮点数,要求精确到小数点右4位(父进程);
② 创建4个子进程,分别求25000个浮点数之和;
③ 父进程完成100000个浮点数之和并打印结果;
④ 统计顺序计算的时间和多个进程采用多道程序设计完成计算的时间。
设计思想:建立一个c语言文件,在main函数的开头先进行初始化处理,如建立一个二维数组double a[4][25000],用来装随机数的数组,将题目要求的十万个浮点数分成四份,每份二万五千个浮点数;再建立一个一维数组double sum[4]={0.0}来装四个子进程的计算浮点数的和。用精确到微秒的结构struct timeval,以及tv_usec来记录顺序计算开始的时刻。通过两个for循环(其中一个for循环嵌套在另一个当中),利用rand()获取随机生成的十万个浮点数。然后创建四个子进程,每个子进程中先计算自己的那份二万五千个浮点数的和,然后写进通道中,然后在父进程中将通道中的计算和打印出来。最后,父进程将所有子进程的和加在一起,完成一个顺序计算,获取顺序计算结束的时刻,接着利用该时刻减去顺序计算开始的时刻,就获得了顺序计算的时间,单位是微秒。
#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;
}
设计原理:在上述的基础上进行改进,同样也是创建四个子进程,每个子进程中先计算自己的那份二万五千个浮点数的和,在子进程开始计算和之前获取该时刻,即子进程运行开始的时刻,然后计算结束后,又获取子进程计算结束后的时刻,用两个时刻相减就获得了单个子进程完成运算所花费的时间(单位:微秒),最后,把计算结果写进通道中,然后在父进程中将通道中的计算和打印出来。
#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系统函数即可创建一个管道。有如下特质: