lab5 Linux进程及并发程序设计 2.docx

上传人:b****6 文档编号:7657642 上传时间:2023-05-11 格式:DOCX 页数:19 大小:391.84KB
下载 相关 举报
lab5 Linux进程及并发程序设计 2.docx_第1页
第1页 / 共19页
lab5 Linux进程及并发程序设计 2.docx_第2页
第2页 / 共19页
lab5 Linux进程及并发程序设计 2.docx_第3页
第3页 / 共19页
lab5 Linux进程及并发程序设计 2.docx_第4页
第4页 / 共19页
lab5 Linux进程及并发程序设计 2.docx_第5页
第5页 / 共19页
lab5 Linux进程及并发程序设计 2.docx_第6页
第6页 / 共19页
lab5 Linux进程及并发程序设计 2.docx_第7页
第7页 / 共19页
lab5 Linux进程及并发程序设计 2.docx_第8页
第8页 / 共19页
lab5 Linux进程及并发程序设计 2.docx_第9页
第9页 / 共19页
lab5 Linux进程及并发程序设计 2.docx_第10页
第10页 / 共19页
lab5 Linux进程及并发程序设计 2.docx_第11页
第11页 / 共19页
lab5 Linux进程及并发程序设计 2.docx_第12页
第12页 / 共19页
lab5 Linux进程及并发程序设计 2.docx_第13页
第13页 / 共19页
lab5 Linux进程及并发程序设计 2.docx_第14页
第14页 / 共19页
lab5 Linux进程及并发程序设计 2.docx_第15页
第15页 / 共19页
lab5 Linux进程及并发程序设计 2.docx_第16页
第16页 / 共19页
lab5 Linux进程及并发程序设计 2.docx_第17页
第17页 / 共19页
lab5 Linux进程及并发程序设计 2.docx_第18页
第18页 / 共19页
lab5 Linux进程及并发程序设计 2.docx_第19页
第19页 / 共19页
亲,该文档总共19页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

lab5 Linux进程及并发程序设计 2.docx

《lab5 Linux进程及并发程序设计 2.docx》由会员分享,可在线阅读,更多相关《lab5 Linux进程及并发程序设计 2.docx(19页珍藏版)》请在冰点文库上搜索。

lab5 Linux进程及并发程序设计 2.docx

lab5Linux进程及并发程序设计2

华南师范大学实验报告

学生姓名学号

专业多媒体与网络技术年级、班级12级多媒体2班

课程名称操作系统原理

实验项目实验5Linux进程及并发程序设计

实验类型验证设计综合实验时间2014年4月22日

实验指导老师实验评分

实验5Linux进程及并发程序设计

一.实验目的:

掌握Linux环境下的进程并发程序及管道应用程序的编写要点。

二.实验内容:

1编写一个并发程序,父进程打印“TheParentisrunning”,子进程打印“TheChildisrunning”。

2编写一个并发程序,父进程打印“TheParentisrunning”,子进程打印“TheChildisrunning”,并保证子进程输出在前,父进程输出在后。

3编写一个管道应用程序,父进程通过管道提供字符串“putthestringintothepipe.”给子进程,子进程通过管道接收这条信息,然后打印输出。

4调试并运行3.10的并发程序设计实例,显示结果是什么,并分析之。

5提高题:

编写一个管道应用程序,使父进程接受用户从键盘输入的数据信息并通过管道传送给子进程,子进程打印输出通过管道接收到的数据信息。

3.实验过程步骤与结果:

(一)编写一个并发程序

1.根据要求编写程序:

#include

main()

{

intp;//存放子进程pid号

while((p=fork())==-1);//创建子进程直到成功为止

if(p==0)//返回值=0表示子进程返回

{

printf("TheChildisrunning\n");

}

else//返回值>0表示父进程返回

{

printf("TheParentisrunning\n");

}

}

2.存放在Linux中的bingfa.c文档中:

3.使用gcc命令对bingfa.c进行编译:

4.多次使用./a.out执行该命令,查看结果:

输出:

TheParentisrunning

TheChildisrunning

或者

TheChildisrunning

TheParentisrunning

5.运行结果分析:

通过实验结果可看出,这是一个并发程序,子进程和父进程在不同的情况下先后出现的顺序可能不同,具有随机性。

(2)编写一个并发程序(子先父后)

1.根据要求编写程序:

#include

#include

main()

{

intp;//存放子进程pid号

while((p=fork())==-1);//创建子进程直到成功为止

if(p==0)//返回值=0表示子进程返回

{

printf("TheChildisrunning\n");

exit(0);

//在子进程结束时调用exit(0),使子进程自我终止,并发终止信号给其父进程;

}

else//返回值>0表示父进程返回

{

wait(0);

//父进程等待子进程终止,再执行下方程序

printf("TheParentisrunning\n");

}

}

2.存放在Linux中的Childfirst.c文档中:

3.使用gcc命令对Childfirst.c进行编译:

4.多次使用./a.out执行该命令,查看结果:

输出:

TheChildisrunning

TheParentisrunning

5.运行结果分析:

从运行结果可看出此程序实现了父等子的功能,始终是子进程先执行。

从代码上看,是用wait(0)和exit(0)实现的,在子进程(p=0)运行后使用exit(0)终止进程,在父进程(p>0)内容程序执行前加上wait(0),使父进程接收到子进程结束的信号后才执行内容程序,从而实现了后执行父进程的效果。

(3)编写一个管道应用程序(父提供给子字符串)

1.根据要求编写程序:

#include

#include

#include//printf函数的头文件

#include//exit函数的头文件

#defineLINESIZE1024

intmain(void)

{

intn,fd[2];

pid_tpid;

charline[LINESIZE];

if(pipe(fd)<0)//调用pipe()函数建立管道;

{

printf("pipeerror");//建立不成功则返回“pipeerror",并退出;

exit

(1);

}

if((pid=fork())<0)//创建进程,创建不成功则返回"forkerror"并退出

{

printf("forkerror");

exit

(1);

}

elseif(pid>0)//父进程的fork()返回

{

close(fd[0]);//关闭管道读指针;

printf("I'mfather~\n");//声明它是父进程

write(fd[1],"putthestringintothepipe.\n",29);

//将"putthestringintothepipe.\n"写入管道

close(fd[1]);//关闭管道写指针;

}

else//父进程的fork()返回

{

close(fd[1]);//关闭管道写指针;

printf("I'mson~\n");//声明它是子进程

n=read(fd[0],line,LINESIZE);

//读取输入的信息,存放到字符串line中

printf("string:

%s\n",line);//输出”string:

“和输入的信息

close(fd[0]);//关闭管道读指针;

}

exit(0);//退出程序;

}

2.存放在Linux中的father_to_son.c文档中:

3.使用gcc命令对father_to_son.c进行编译:

4.使用./a.out执行该命令,查看结果:

输出:

I'mfather~

I'mson~

string:

putthestringintothepipe.

5.运行结果及程序思路分析:

通过pipe()函数建立管道;用close(fd[0])关闭父进程管道读指针,利用write(fd[1],"字符串内容",字符串长度);写入字符串,最后关闭管道写指针;用close(fd[1])关闭子进程管道写指针,利用read(fd[0],"字符串内容",字符串长度);读取管道中字符串,最后关闭管道读指针;实现父进程向子进程传递字符串的功能;

(四)调试运行3.10并发程序并进行分析

1.程序源代码如下:

【father1.c】:

【child1.c】:

【pipeline.c】:

2.执行程序:

输入:

cc-ochild1child1.c

cc-ofather1father1.c

ccpipeline.c

./a.out

输出:

_Parentisusingpipewrite.

child,child.

3.代码与运行结果分析:

【father1.c】:

#include

#include

main()

{

staticcharstring[]="Parentisusingpipewrite.";

intlen;

len=sizeof(string);

write(1,string,len);

//将"Parentisusingpipewrite."写入字符串len中

printf("parent,parent,parent\n\n\n");

//输出显示是parent进程在执行

exit(0);

}

【child1.c】:

#include

main()

{

charoutput[30];

read(0,output,30);//读output中的内容

printf("_%s\nchild,child.\n",output);

//输出output中的内容加上child,child声明是子进程

return(0);

}

【pipeline.c】:

#include

#include

#include

#defineSTD_INPUT0//定义标准输入设备描述符

#defineSTD_OUTPUT1//定义标准输出设备描述符

intfd[2];

main()

{

staticcharprocess1[]="father1",process2[]="child1";

pipe(fd);//定义管道,返回文件描述符fd[0],fd[1]

pipeline(process1,process2);//调用自定义函数pipeline();

exit

(1);//程序结束

}

pipeline(process1,process2)

char*process1,*process2;

{

inti;

while((i=fork())==-1);

//创建进程,创建失败则反复创建,直到创建成功

if(i)//父进程的fork()返回

{

close(fd[0]);//关闭管道读端

close(STD_OUTPUT);

//关闭标准输出描述符1(原来是写到显示器的指针)

dup(fd[1]);

//指定标准输出描述符1为管道写指针,语句后调用printf函数,那么内容并不会输出到显示器,而是写入了管道中。

close(fd[1]);//关闭原始管道写指针

execl(process1,process1,0);//用程序father1覆盖当前程序

printf("——fatherfailed.\n");//execl()执行失败时才执行这一行

}

else

{

close(fd[1]);//关闭管道写端

close(STD_INPUT);//关闭标准输出描述符0

dup(fd[0]);//指定标准输入描述符0为管道读指针,语句后调用scanf函数,那么不会从键盘读取内容,而是从管道中读取。

close(fd[0]);//关闭原始管道读指针

execl(process2,process2,0);//用程序child1覆盖当前程序

printf("——childfailed.\n");//execl()执行失败时才执行这一行

}

exit

(2);//程序结束

}

4.运行结果分析:

输出结果为:

_Parentisusingpipewrite.child,child.

Pipeline.c中调用了dup(fd[1]);指定标准输出描述符1为管道写指针,语句后调用printf函数,那么内容并不会输出到显示器,而是写入了管道中。

而从结果可看出,父进程通过管道传给了子进程“Parentisusingpipewrite.”(从而才会前面有_,后面有child,child),同时pipeline.c中使用execl(process1,process1,0);用父进程覆盖原进程,如果没有发挥dup(fd[1])的作用(将printf中的内容“parent,parent,parent”写入管道中),也应在界面中打印出来。

所以我进行了以下几个测试:

(1)测试printf是否因write而没有输入到管道中(注释掉write行)

输出了:

_parent,parent,parent(3行)child,child

出现了“_”和“child,child”,说明dup(fd[1])的作用实现了,prinf的内容的确输入到管道中。

说明是write导致的。

(2)测试是否由于write和printf的顺序导致无法写入(调换位置)

仍然无法输出,说明不是顺序问题;

(3)测试是否发送接收字符串的问题(是否结束符\0的问题)

修改发送字符串长度:

后面出现的pa说明的确是字符串长度的问题;

接下来修改接收字符串长度:

成功实现prinf内容输入管道并从子进程同时读取出用write和prinf写入的内容。

分析字符串长度为何会导致这种问题:

通过上网了解到,用sizeof计算变量的空间大小时,它会把数组末尾的\0符号也计算进去,在你往管道内输入后,读取时遇见'\0'符号就会认为字符串结束,就不再读取prinf中的内容,而prinf中的内容,不管与write命令的顺序如何,都只会把内容输入到管道中write的部分。

从而,整个程序利用execl();实现father1和child1在同一程序中实现,father1通过管道通信传给了child1字符串;同时利用close(fd[])的方式实现进程的互斥。

使用dup(fd[])实现将外部输入输出设备的信息置于管道中,进行读取。

(五)编写一个管道应用程序(父接收键盘输入传给子进程)

1.根据要求编写程序:

#include

#include

#include

#include

#include

#include

#defineLINESIZE1024

intmain(void)

{

intn,fd[2];

pid_tpid;

charline[LINESIZE];

fgets(line,sizeof(line),stdin);//获得键盘输入,存放在字符串line中

if(pipe(fd)<0)//调用pipe()函数建立管道;

{

printf("pipeerror");//建立不成功则返回“pipeerror",并退出;

exit

(1);

}

if((pid=fork())<0)//创建进程,创建不成功则返回"forkerror"并退出

{

printf("forkerror");

exit

(1);

}

elseif(pid>0)

{

close(fd[0]);//关闭管道读指针

printf("I'mfather~\n");//声明它是父进程

write(fd[1],line,sizeof(line));//将line中的内容(即键盘输入)写入管道中

close(fd[1]);//关闭管道写指针

}

else//子进程的fork()返回

{

close(fd[1]);//关闭管道写指针;

printf("I'mson~\n");//声明它是子进程

n=read(fd[0],line,LINESIZE);

//读取输入的信息,存放到字符串line中

printf("string:

%s\n",line);//输出”string:

“和输入的信息

close(fd[0]);//关闭管道读指针

}

exit(0);//退出程序;

}

2.存放在Linux中的key_father.c文档中:

3.使用gcc命令对key_father.c进行编译:

4.使用./a.out执行该命令,查看结果:

输入:

I’mYidan!

!

!

yeyeye

输出:

I'mfather~

I'mson~

string:

I’mYidan!

!

!

Yeyeye

输入:

yes!

输出:

I'mfather~

I'mson~

string:

yes!

5.运行结果分析:

通过fgets(字符数组名,字符数字长度,stdin)获取键盘输入;通过pipe()函数建立管道;用close(fd[0])关闭父进程管道读指针,利用write(fd[1],要写入的字符串,字符串长度);写入字符串,最后关闭管道写指针;用close(fd[1])关闭子进程管道写指针,利用read(fd[0],要写入的字符串字符串长度);读取管道中字符串,最后关闭管道读指针;实现父进程向子进程传递字符串的功能;

与实验三直接在代码中加入字符串的区别在于用fgets(字符数组名,字符数字长度,stdin)获取键盘输入,并将其存放在该字符数组中,在进行传递字符时,直接使用字符数组名进行传递。

4.实验总结与反思

通过这次实验了解到wait();exit();fget(;;stdin);pipe(fd[2]);close(fd[0]);dup(files);等句子在进程间通信的使用,知道通信间的一些逻辑关系,学会如何改变父子进程执行顺序的先后、如何实现父子进程间信息的传递,受益匪浅。

关于每个程序的分析已附在每个程序代码注释和运行结果分析。

同时,实验过程多与别人讨论,多输入不同的数据,稍微改动程序进行尝试,都会使自己从更多的角度来看待问题,解决问题,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 初中教育 > 理化生

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2