操作系统linux环境下的fork()进程创建以及fork()与fork()的区别

fork()函数的理解:
含义: os.fork()函数会从调用此函数的地方创建出子进程,子进程会与主进程(即父进程)一起在CPU内执行。
注意:os.fork()函数只在linux环境下才有用,如果是windows环境下,会报错 no os.fork()。
1、每个进程都有一个独特(互不相同)的进程标识符(process ID),可以通过getpid()函数获得,还有一个记录父进程pid的变量,可以通过getppid()函数获得变量的值。

fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:

返回值为0,代表当前进程是子进程;
返回值为非负数(>0),代表当前进程是父进程
调用失败,返回-1

直接返回getpid()的值,则表示当前进程PID

在这里插入图片描述

2、使用fork函数创建一个进程,实验举例

#include <sys/types.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
    
    
	pid_t pid;
	pid=fork();    //创建子进程
	if(pid<0)
		printf("error in fork");
	else if(pid==0)
		printf("I am the child process,ID is %d\n", getpid());
	else
		printf("I am the parent process,ID is %d\n", getpid());
}

运行结果:

  I am the child process,ID is 2723

  I am the parent process,ID is 2722

实验程序分析:
1)pid=fork();
  先来看看子进程的表现:
  操作系统调用fork()函数创建一个新的进程(子进程),并且在进程表中相应为它建立一个新的表项,
  此时子进程得到CPU的调度,它的上下文被换入,占据 CPU,操作系统对fork的实现,使得子进程中fork调用返回0
  所以在这个进程中pid=0,这个进程继续执行的过程中,if语句中 pid<0不满足,但是pid= =0是true。所以输出i am the child process…
  
  父进程的表现:
  操作系统对fork的实现,使这个调用在父进程中返回刚刚创建的子进程的pid(一个正整数),所以下面的if语句中pid<0,pid==0的两个分支都不会执行。所以输出i am the parent process…
  
  2)对子进程来说,fork返回给它0,但它的pid绝对不会是0,之所以fork返回0给它,是因为它随时可以调用getpid()来获取自己的pid
  
  3)fork之后父子进程除非采用了同步手段,否则不能确定谁先运行,也不能确定谁先结束.认为子进程结束后父进程才从fork返回的,这是不对的,fork不是这样的,vfork才这样。
  
  4)父进程执行了所有的进程,而子进程只执行了fork()后面的程序,这是因为子进程继承了父进程的PC(程序计数器).

vfork与fork的区别

  vfork与fork主要有三点区别:

  .fork():子进程拷贝父进程的数据段,堆栈段

  vfork():子进程与父进程共享数据段

  .fork()父子进程的执行次序不确定vfork 保证子进程先运行,在调用 exec 或 exit 之前与父进程数据是共享的,在它调用 exec或 exit 之后父进程才可能被调度运行。

  .vfork()保证子进程先运行,在它调用 exec 或 exit 之后父进程才可能被调度运行.如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。

(1)先用fork()进行试验

#include <unistd.h>
#include <stdio.h>
int main(void)
{
    
    
  pid_t pid;
  int count=0;
  pid=fork();
  count++;
  printf("count= %d\n",count);
  return 0;
}

分析:

通过上面fork()的说明,这个程序的输出应该是:

./test

count= 1

count= 1

(2)而将fork()换成vfork()呢,程序如下

#include <unistd.h>
#include <stdio.h>
int main(void)
{
    
    
	pid_t pid;
  int count=0;
  pid=vfork();
  count++;
  printf("count= %d\n",count);
  return 0;
}

./test 执行结果:

count= 1

count= 1

Segmentation fault (core dumped)

分析:

通过将fork()换成vfork(),由于vfork()是共享数据段,为什么结果不是2呢?

答案是: vfork保证子进程先运行,在它调用 exec 或 exit 之后父进程才可能被调度运行.如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁.

(3)做最后的修改,在子进程执行时,调用_exit(),程序如下:

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
int main(void)
{
    
    
	pid_t pid;
  int count=0;
  pid=vfork();
  if(pid==0)
  {
    
    
  count++;
  _exit(0);
  }
  else
  {
    
    
  count++;
  }
  printf("count= %d\n",count);
  return 0;
}

./test 执行结果:
  count= 2

分析:如果子进程中如果没有调用_exit(0),则父进程不可能被执行,在子进程调用exec(),exit()之后父进程才可能被调用.

所以加上_exit(0),使子进程退出,父进程执行.

这样 else 后的语句就会被父进程执行,又因在子进程调用 exec 或 exit 之前与父进程数据是共享的,

所以子进程退出后把父进程的数据段 count 改成1了,子进程退出后,父进程又执行,最终就将count 变成了 2.

猜你喜欢

转载自blog.csdn.net/forever_up422/article/details/124819514