实验三 进程管理及进程通信
                       
实验环境:
Linux操作系统
实验目的:
(1)利用Linux提供的系统调用设计程序,加深对进程概念的理解。
(2)体会系统进程调度的方法和效果。
(3)了解进程之间的通信方式以及各种通信方式的使用。
实验方法:
vi 编写c 程序假定程序文件名prog1.c) 编译程序
$ gcc -o prog1.o prog1.c
$ cc -o prog1.o prog1.c
运行
$./prog1.o
实验内容及步骤:
实验1
编写程序。显进程有关标(进标识识、用标识)。5 秒钟后,执另一程序按用户示(如:Y/N束操作。
编程截图:
运行结果:
实验2
参考例程1,写程序。实现父程创一个。体会进程父进别获得不同返值,而执的程序的方
例程1利用fork()创建子
/* 用fork()系统调创建进程的进程通信方式例*/
main()
{
int i;
if (fork())      /*父进程执行的程序*/
  i=wait();        /* 等待子进程结*/{
printf("It is parent process.\n");
printf("The child process,ID number %d, is finished.\n",i);
}
else{
    Printf(It is child process.\n);
    Sleep(10);
Exit();
}
}
  运行结果:
思考:
进程如何生的? 如何束的子进程创建它的境是怎 样建立
答:是由父进程用fock()函数创建形成的,通过exit()函数自我结束,子进程被创建后核心
将其分配一个进程表项和进程标识符,检查同时运行的进程数目,并且拷贝进程表项的数据,由子进程继承父进程所有文件。
实验3
参考例程2,写程序。父进程过循语句干子进。探进程树以 及子进继承进程的关系。
例程2循环fork()多个子程。
/*进程*/
#include<unistd.h>
main()
{ int i;
printf(My pid is %d, my father’s pid is %d\n”,getpid()
,getppid());
for(i=0; i<3; i++)
if(fork()==0)
printf(%d pid=%d ppid=%d\n”, i,getpid(),getppid());
else
{ j=wait(0);
Printf( %d:The chile %d is finished.\n” ,getpid(),j);
}
}
运行结果:
思考:
① 画出进程的家族树。
答:进程家族树
实验4
参考例程3 编程使fork( )和exec( )等系统调创建三子进。子别启动
不同程,并束。行该程,观运行结束的是否次 序。
例程3:创建进程execlp()系统调执行序的
/*子进,子程启其它程*/
#include<stdio.h>
#include<unistd.h>
main()
{
int child_pid1,child_pid2,child_pid3;
int pid,status;
setbuf(stdout,NULL);
child_pid1=fork();    /*创建进程1*/
if(child_pid1==0)
{ execlp("echo","echo","child process 1",(char *)0); /*进程1 启动其它程*/
perror("exec1 error.\n ");
exit(1);
}
child_pid2=fork();    /*创建进程2*/
if(child_pid2==0)
{ execlp("date","date",(char *)0);    /*子进程2 启动其它程序*/
perror("exec2 error.\n ");
exit(2);
}
child_pid3=fork();    /*创建进程3*/
if(child_pid3==0)
{ execlp("ls","ls",(char *)0);    /*子进程3 启动其它程序*/
perror("exec3 error.\n ");
exit(3);
}
puts("Parent process is waiting for chile process return!");
while((pid=wait(&status))!=-1)    /*等待子进程结束*/
{ if(child_pid1==pid)    /*若子进程1 结束*/
printf("child process 1 terminated with status %d\n",(status>>8));
else
{if(child_pid2==pid)    /*若子进程2 结束*/
printf("child process 2 terminated with status %d\n",(status>>8));
else
{ if(child_pid3==pid)    /*若子进程3 结束*/
printf("child process 3 terminated with status %d\n" ,(status>>8));
}
}
}
puts("All child processes terminated."); puts("Parent process terminated."); exit(0);
}
运行结果:
思考:
子进程运行其它程序后,进程运行环境怎样变化的?反复运行此程序看会有
什么情况?解释一下。
答:子进程运行其他程序后,这个进程就完全被新程序替代。由于并没有产生新进程,所以进程标识号不变,除此之外的旧进程的其他信息,代码段,数据段,栈段等均被新程序的信息所替代。新程序从自己的main()函数开始进行。反复运行此程序发现结束的先后次序是不可预知的,每次运行的结果不一样。原因是当每个子进程运行其他程序是,他们的结束随着其他程序的结束而结束,所以结束的先后次序在变化。
实验5
参考例程4 编程,验证子进程继承父进程的程序、数据等资源。如用父、子进程修改 公共变量和私有变量的处理结果;父、子进程的程序区和数据区的位置。
例程4:观察父、子进程对变量处理的影响
/*创建子进程的实验。子进程继承父进程的资源,修改了公共变量globa 和私有变 量vari。观察变化情况。*/
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int globa=4;
int main()
{
pid_t pid; int vari=5; printf("before fork.\n");
if ((pid=fork())<0)/*创建失败处理*/
{
printf("fork error.\n");
exit(0);
}
else if(pid==0)
{    /*子进程执*/
globa++;
vari--;
printf("Child %d changed the vari and globa.\n",getpid());
}
else    /*父进程执*/
printf("Parent %d did not changed the vari and globa.\n",getpid());
printf("pid=%d, globa=%d, vari=%d\n",getpid(),globa,vari);    /*都执*/
exit(0);
}
运行结果:
思考:
进程创建,对父程的行环响吗?释一
答:父进程被创建后,对父进程的运行环境无影响,因为当子进程在运行时,他有自己的代码段和数据段,这些都可以做修改。但是父进程的代码和数据段是不会随着子进程数据段和代码段的改变而改变。
实验6
参照《实验指导》第五部分中“管道操作的系统调用”。复习管道通信概念,参考例 程5,编写一个程序。父进程创建两个子进程,父子进程之间利用管道进行通信。要 求能显示父进程、子进程各自的信息,体现通信效果。
例程5:管道通信的实验
/*程序建立一个管道fd*/
/*父进程创建两个子进程P1、P2 */
/*子进程P1、P2 分别向管道写入信息*/
/*父进程等待子进程结束,并读出管道中的信息*/
#include<stdio.h>
main()
{
int i,r,j,k,l,p1,p2,fd[2];
char buf[50],s[50];
pipe(fd); /*建立一个管道fd*/   
while((p1=fork())==-1);  /*创建子进程1*/
if(p1==0)
lockf(fd[1],1,0);    /*子进程1 执行*/
/*管道写入端加*/
{
sprintf(buf,"Child process P1 is sending messages! \n");
printf("Child process P1! \n");