fork函数与vfork函数的差别

fork函数

头文件:#include<unistd.h>
函数原型:pid_t fork(void)
功能:它是从已经存在的进程中创建一个新进程,
     新进程为子进程,而原来的进程为父进程

1.fork函数的返回值情况
这里写图片描述
ps:子进程返回0,父进程返回子进程的pid。

2.父进程与子进程之间的关系

(1)子进程是以父进程为模板的,数据结构一样;
(2)代码共享一份(也就是两个进程共同使用同一份代码,但每个进程会因为fork的返回值从而进入不同的选项);
(3)父进程和子进程的内存指针相同;
(4)子进程会继承父进程的环境变量;
(5)pid不相同,父进程和子进程都有各自的pid(ps:每个进程都有自己的pid,不会跟别的进程相同,此pid是唯一的)
(6)fork之后,父进程和子进程之间的执行顺序不确定,谁先执行谁后指向是根据系统决定的。
(7)父进程的数据和子进程的数据各自有各自的虚拟地址空间。

3.fork调用失败的原因

主要原因
(1)系统中有太多的进程;
(2)实际用户的进程数超过了限制;
其他原因
(1)内存不足;
(2)系统不支持‘

4.fork常规用法

(1)一个父进程希望复制自己,使子进程同时执行不同的代码。例如:父进程等待客户端请求,生成子进程处理请求;
(2)一个进程要执行一个不同的程序。

5.例子
(1)代码:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
 {
   pid_t pid;//pit_t是无符号的整型
   printf("Before :pid is %d\n",getpid());
   pid = fork();//创建子进程
   if(pid<0)
   {
     perror("fork");
     exit(1);
   }
   printf("After:pid is %d,fork return %d\n",getpid(),pid);
   return 0;
}

运行结果:
这里写图片描述

解释:此例子说明,fork之后会有两个返回值,父进程返回的是子进程的pid,而子进程返回的是0
(2)代码:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
  pid_t pid;
  int count = 0;
  pid = fork();
  if(pid<0)
  {
    perror("fork()");
    exit(1);
  }
  else if(pid>0)
  {
   count += 2;
   printf("this is the father process.\n");
   printf("pid is %d,fork return %d\n",getpid(),pid);
   //getpid()函数是返回当前进程的pid
   printf("count = %d\n",count);
  }
  else
  {
   count++;
   printf("this is the child  process.\n");
   printf("pid is %d,fork return %d\n",getpid(),pid);
   printf("count = %d\n",count);
  }
  return 0;
}

运行结果:
这里写图片描述
解释:此例子说明,子进程和父进程各自有各自的数据空间,因为count有两个不同的结果,而且也说明,子进程和父进程共享一份代码,但是谁走哪个选项,就会根据pid决定

vfork函数

头文件:#include<unistd.h>
函数原型:pid_t vfork(void)
功能:Vfork和fork一样,都是在已有的进程中创建一个新的进程,
     但是vfork创建的子进程和fork创建的子进程是有区别的

1.vfork返回值的情况
和fork的返回值一样,都是子进程中返回0,父进程中返回子进程的id
2.父进程与子进程之间的关系

(1)父进程和子进程共享一份地址空间;
(2)vfork保证子进程先运行,在它调用exex或exit函数之后父进程才会被调度运行

ps:因为子进程和父进程共用一份地址空间,而且子进程先执行,所以子进程会修改父进程中的变量值。
3.例子
分别使用fork函数vfork函数修改同一个全局变量
(1)代码

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int g_val=100;//定义一个全局变量
int main()
{
   pid_t pid;
   pid = fork();
   if(pid<0)
   {
     perror("fork()");
     exit(1);
   }
   if(pid==0)
   {
    printf("this is the child process.\n");
    sleep(5);
    g_val = 200;
    printf("g_val= %d\n",g_val);
   }
   else
   {
    printf("this is the father process.\n");
    printf("g_val=%d\n",g_val);
   }
   return 0;
}

运行结果:

这里写图片描述
(2)代码

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int g_val=100;//定义一个全局变量
int main()
{
   pid_t pid;
   pid = vfork();
   if(pid<0)
   {
     perror("vfork()");
     exit(1);
   }
   if(pid==0)
   {
    printf("this is the child process.\n");
    sleep(5);
    g_val = 200;
    printf("g_val= %d\n",g_val);
    exit(0);
   }
   else
   {
    printf("this is the father process.\n");
    printf("g_val=%d\n",g_val);
   }
   return 0;
}

这里写图片描述

这两个例子说明,fork出来的父进程和子进程有自己的独立地址空间,而vfork出来的父进程和子进程共用一份地址空间,所以vfork出来的子进程会修改父进程的变量值,因为子进程在父进程的地址空间中运行。

其他创建进程的方式
clone

clone函数允许子进程共享一部分父进程的数据

system

是对fork的封装,system函数在等待命令终止时将忽略SIGINT和SIGQUIT信号,同时阻塞SIGCHLD信号
这会导致应用程序错过一个人终止它的信号,,故应用程序应该检查system函数的返回值,如果由于收到某个信号而终止了命令,应用程序应采取一切适当的措施

popen

也是对fork的封装,popen函数会打开一个管道用于进程间通信

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值