《计算机操作系统》—— Linux进程通信

Linux进程通信

在Linux环境下,用c语言编程,使用系统调用fork创建进程多个子进程。
fork():建立子进程。子进程得到父进程地址空间的一个复制。
返回值:成功时,该函数被调用一次,但返回两次,fork()对子进程返回0,对父进程返回子进程标识符(非0值)。不成功时对父进程返回-1,没有子进程。
(1) 调试并完成下列程序,完成实验要求:

#include "stdio.h"
int main()
{
 int pid1;
int pid2;
pid1 = fork();
pid2 = fork();
printf("pid1:%d, pid2:%d\n", pid1, pid2);
return 0;
}

要求:
A.请说出执行这个程序后,将一共运行几个进程。
B.观察运行结果,并给出分析与解释。
答:(执行程序的相关步骤)
在这里插入图片描述
在这里插入图片描述
编辑源程序:
在这里插入图片描述
命令行下编辑:
在这里插入图片描述
A:4个进程
B:运行结果为:
在这里插入图片描述
分析:
fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。
fork()返回值意义如下:
0:在子进程中,pid变量保存的fork()返回值为0,表示当前进程是子进程
>0:在父进程中,pid变量保存的fork()返回值为子进程的ID值(进程唯一表示符)。

我们可以根据返回值的不同来判断先执行父进程还是子进程。
1、执行此程序,启动了一个进程,我们设这个进程为P0,设其PID为XXX(解题过程不需知道其PID)。
2、当执行到pid1 = fork();时,P0启动一个子进程P1,由运行结果知P1的PID为2597。我们暂且不管P1。
3、P0中的fork返回2597给pid1,继续执行到pid2 = fork();,此时启动另一个新进程,设为P2,由运行结果知P2的PID为2598。同样暂且不管P2。
4、P0中的第二个fork返回2598给pid2,继续执行完后续程序,结束。所以,P0的结果为“pid1:2597, pid2:2598”。
5、再看P2,P2生成时,P0中pid1=2597,所以P2中pid1继承P0的2597,而作为子进程pid2=0。P2从第二个fork后开始执行,结束后输出“pid1:2597, pid2:0”。
6、接着看P1,P1中第一条fork返回0给pid1,然后接着执行后面的语句。而后面接着的语句是pid2 = fork();执行到这里,P1又产生了一个新进程,设为P3。先不管P3。
7、P1中第二条fork将P3的PID返回给pid2,由运行结果知P3的PID为2599,所以P1的pid2=1003。P1继续执行后续程序,结束,输出“pid1:0, pid2:2599”。
8、P3作为P1的子进程,继承P1中pid1=0,并且第二条fork将0返回给pid2,所以P3最后输出“pid1:0, pid2:0”。
9、至此,整个执行过程完毕。

(2)首先分析一下程序运行时其输出结果有哪几种可能性,然后实际调试该程序观察其实际输出情况,比较两者的差异,分析其中的原因。

void main ()
{    int   x=5;
      if( fork( ) )
        {
x+=30;
             printf (“%d\n”,x);
         }
       else 
          printf(“%d\n”,x);
    printf((“%d\n”,x);
}

1.预计实验结果:
猜测有6种情况:

35	35	35	5	5	5 
35	5	5	5	35	35
5	35	5	35	5	35
5	5	35	35	35	5

2.实际输出情况:
在这里插入图片描述
3.分析:
当这个程序执行if(fork())时,系统创建一个新的进程(子进程), 新进程绝大部分是复制原进程,但他们相互独立。
在父进程中,fork()函数返回刚刚创建的子进程的pid,且这个pid不为0,所以程序执行x+=30和printf(“%d\n,x”),所以父进程输出的x值为35。

在子进程中,fork()函数返回0, 所以程序执行printf(“%d\n”,x),因为子进程从父进程那里得到的x赋值为5,且没有被重新赋值,所以输出x的值为5。
在两个进程中,都会执行最后一条程序printf((“%d\n”,x)。

因为这个程序运行所需的时间实在是太短,默认先运行的父进程完全可以在系统给定的时间片内运行完,如果没有出现什么其他情况而挂起,子进程就只能等到父进程运行完后才能运行。所以得到如上输出结果。

(3)参考下面的相关程序实例,编写一个管道实验程序,实现两个进程之间的数据通信。
要求:父进程顺序写入26个英文字符(或其他),子进程读出相应内容,并写入文件pipo.txt,并显示出来。

1.设计步骤:
第一步:用pipe()创建一个管道fd (fd[0]用于读管道,fd[1]用于写管道)
第二步:用fork产生两个进程:父进程与子进程
第三步:把父进程的字符串写入管道,写完后关闭写端
第四步:子进程读取父进程传输的信息,关闭读端

2.数据结构:定义一个字符串数组str[26]用于存放父进程将要传送给子进程的消息。
3.关键代码:

#include “stdio.h”
#include “string.h”
int main()
{
	char str[50]="I’m a hardworking student.";
	int fd[2], childpid;           // fd[0]用于读管道,fd[1]用于写管道
	if (pipe(fd)<0)                       //创建管道如果失败
	{
		printf("pipe() error\n");
		return -1;
	}
	childpid=fork();
while((childpid=fork())==-1);         //直至创建成功
	if (childpid==0)            //子进程fork()=0  所以子进程做读操作
	{
		close(fd[1]);                      //关闭写端
		read(fd[0],str,sizeof(str));       //从管道口fd[0]读内容
		FILE *fp;
		fp=fopen("pipo.txt","w");         //创建文件
		fprintf(fp,"%s\n",str);             //写入文件
		fclose(fp);
		return 0;
	}
else         //父进程fork()返回子进程的PID!=0,所以父进程做写操作
{      
		close(fd[0]);                     //关闭读端
		write(fd[1],str,strlen(str));       //从管道口fd[1]写内容
		return 0;
	}
}

4.实验结果:
在这里插入图片描述
5.分析说明:
父进程调用pipe函数创建管道,得到两个文件描述符fd[0]、fd[1]指向管道的读端和写端。
父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管道。
父进程关闭管道读端,子进程关闭管道写端。父进程可以向管道中写入数据,子进程将管道中的数据读出。由于管道是利用环形队列实现的,数据从写端流入管道,从读端流出,这样就实现了进程间通信。

猜你喜欢

转载自blog.csdn.net/qq_39480875/article/details/86674170
今日推荐