龙空技术网

Linux系列6_函数返回值只能一个?你错了-fork函数

deeplearning爱好者 189

前言:

今天我们对“c语言fork”大约比较珍视,咱们都想要了解一些“c语言fork”的相关知识。那么小编在网摘上收集了一些对于“c语言fork””的相关文章,希望大家能喜欢,朋友们快快来了解一下吧!

接上文 Linux系列5_你知道什么是进程以及如何查进程吗?

(4)创建进程-forkA:fork的作用:演示

fork()函数是用来创建进程的,在fork函数执行后,如果成功创建新进程就会出现两个进程,一个是子进程,一个是父进程,fork函数有两个返回值

1:演示一:创建子进程

编写如下C语言文件,进入主函数后,执行fork函数,创建进程

#include <stdio.h>#include <unistd.h>int main(){	printf("执行到fork函数之前其进程为:%d,其父进程为:%d\n",getpid(),getppid()); 	sleep(1);	fork();	sleep(1);	prinf("这个进程id为:%d,它的父进程id为%d\n",getpid(),getppid());	sleep(1);	return 0;}

运行效果如下

根据上面程序的运行效果,似乎可以发现下面比较值得注意的几点

它们的逻辑关系有些特点从上面的动图可以发现,fork()函数调用完成之后,**它们似乎是同时输出的,这是否告诉我们这两个进程是同时进行的?**或许它可以被画成这样?

2:演示二:创建子进程

前面说过,fork有两个返回值。官方手册中是这样解释到的

在父进程中,fork返回新创建子进程的ID在子进程中,fork返回0未能创建,fork返回负值

在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的ID。我们可以通过fork返回值判断当前进程是什么进程。

根据以上描述,编写C语言代码,使用fork函数的返回值来进行分流

#include <stdio.h>#include <unistd.h>int main(){	prinf("还没有执行fork函数的本进程为:%d\n",getpid());	pid_t=fork();//其返回值是pid类型的	sleep(1);		if(ret>0)//父进程返回的是子进程ID		printf("我是父进程,我的id是:%d,我的孩子id是%d\n",getpid(),ret);	else if(ret==0)//子进程fork返回值是0		printf("我是子进程,我的id是%d,我的父亲id是%d\n",getpid(),getppid());	else		printf("进程创建失败\n");			sleep(1);	return 0;}

效果如下

3:演示三:一个大的问题

为了方便演示,修改上述代码如下,为每个if语句块内加入死循环,使其不能不断输出

#include <stdio.h>#include <unistd.h>int main(){	prinf("还没有执行fork函数的本进程为:%d\n",getpid());	pid_t=fork();//其返回值是pid类型的	sleep(1);		if(ret>0)//父进程返回的是子进程ID	{		while(1)		{			printf("----------------------------------------------------------------\n");			printf("我是父进程,我的id是:%d,我的孩子id是%d\n",getpid(),ret);			sleep(1);		}	}	else if(ret==0)//子进程fork返回值是0	{		while(1)		{			printf("我是子进程,我的id是%d,我的父亲id是%d\n",getpid(),getppid());			sleep(1);		}	}	else		printf("进程创建失败\n");			sleep(1);	return 0;}

效果如下

同时再使用之前的命令查看这个进程,发现也是两个进程

但是这里有一个很大的问题:不过是什么语言,if-else执行时每次只能执行一路,怎么可能同时执行多路,同时每个if语句块内都有死循环,一个循环未结束,又怎么可能去执行其他语句呢

在Linux中,进程创建会形成链表,父进程创建子进程,那么父进程的进程指针会指向子进程ID。

所以这两个进程是同时运行的

B:fork相关问题

1.如何理解进程创建

前面说过,操作系统在进行管理时,必然遵循“先描述,再组织”的原则,所以在进行进程管理时。首先会创建相应的task_struct,写入有关信息,然后和你编写好的代码共同组成进程

2.为什么fork有两个返回值

根据上面的描述,可以大致描述fork函数的执行逻辑如下

pid_t fork(){	//先描述,再组织,所以首先为子进程创建结构体	struct task_struct* p=malloc(struct task_struct);	//以下逻辑就是写入属性信息	p->XX=father->XX;	....	p->status=run;	p->id=1888;		//到这里之前,子进程创建完毕	return p->id;}

其实,进程数据=代码+数据,代码是共享的,数据是私有的,上述逻辑中return之前的语句是父进程执行,结果就是生成了子进程,等执行return语句时,子进程已经生成,于是父子进程同时执行这一条语句,又因为数据是私有的,所以各自返回不同的值

执行完fork之后,父进程pid不等于0,子进程pid等于0。这两个进程都是独立的,存在于不同地址中,不是公用的。

fork把进程当前的情况进行拷贝,执行fork时,fork只拷贝下一个要执行的代码到新的进程

为了说明变量不共用,可以编写一个C语言代码如下,同一个变量分别在父进程和子进程中修改

#include <stdio.h>#include <unistd.h>int main(){  int cout=0;  printf("还未执行fork函数的cout=%d\n",cout);  pid_t ret=fork();  if(ret>0)  {    cout+=1;//父进程cout=1;    printf("父进程:cout=%d\n",cout);  }  else if(ret==0)  {    cout+=10;//子进程cout=10;    printf("子进程:cout=%d\n",cout);  }  else     printf("失败\n");  sleep(1);  return 0;  }

结果如下,可以发现它们不公用变量

3.为什么两个返回值不一样

其实很好理解,创建进程时相当于形成了链表(Linux)中,父进程指向子进程,所以返回的是子进程的ID,而子进程没有它的子进程,所以返回0。

标签: #c语言fork