入门理解:fork() 与 vfork()

进程号的获取

在Linux运行一个程序时,系统会分配相应的进程ID,getpid()函数返回值为本程序的运行时的进程号,getppid()函数返回值为创建此进程的父进程的进程号,进程ID类似文件描述符,方便系统管理调度。

为什么要创建子进程?

我认为,主要为了提高运行效率,创建子进程才能多道程序并发执行,进程是资源分配的单位,是运行的程序。既然是运行的程序,一个进程自然只能代表一个程序,多道程序设计自然而然就有了多进程的概念。举个例子,多进程(线程)下载,我们可以给一个需要下载的资源分片,多个进程从不同的片分时下载,这样就提高了下载速度,因为对一个程序分配的更多的资源,你试试开迅雷的时候打开个网页,保证你觉得奇卡无比,因为网络带宽(资源)被迅雷的多个进程占用了。其实在本地的多进程程序并不多见,比如word算是个典型的多进程程序,有个进程接受你的键盘输入,有拼写检查进程,有显示进程等等。大多数都用到网络上了,比如服务器。一台服务器要在“同一时间”处理来自很多客户端的请求,这就必须使用多进程。

进程创建函数fork()

fork()函数没有参数,在子进程中返回值为0;在父进程中返回值为父进程所创建子进程的进程号,可以当做链表来理解

父进程->子进程->NULL;如果进程创建失败则返回一个负数。

示例代码如下:

#include <unistd.h>  
#include <stdio.h> 
#include <sys/types.h>  
int main ()   
{   
    pid_t fpid; //fpid表示fork函数返回的值  
    fpid=fork();   
    if (fpid < 0)   
        printf("error in fork!");   
    else if (fpid == 0) {  
        printf(" child process id is %d\n",getpid());   
        printf("child's father process id is %d\n",getppid());
    }  
    else {  
        printf("father's process id is %d\n",getpid());
 } return 0; 
} 
程序运行结果如下所示:

[root@localhost fork]# gcc fork.c -o run
[root@localhost fork]# ./run 
father's process id is 4101
child process id is 4102
child's father process id is 4101
打印结果可以看出

父进程ID为4101 子进程ID为4102 父进程指向子进程。

如果子进程输出自身ID后,添加延时或者执行其它任务之后,再次打印父进程ID会发现,父进程ID变为1,这是因为,父子进程创建完毕时几乎是“同时”运行,子进程运行时间较长,运行到打印父进程ID时,父进程已经结束,此时子进程变为孤儿进程,由系统进程 1 进行暂时领养。

关于fork 与 vfork区别这里指两个例子

首先是fork()代码如下

#include <unistd.h>  
#include <stdio.h> 
#include <sys/types.h>  
int main ()   
{   
    pid_t fpid; 
    int  count=0;
    fpid=fork();   
    count++;
    printf("count is %d\n",count);
 return 0; 
} 
运行结果如下:

[root@localhost fork]# gcc fork.c -o run
[root@localhost fork]# ./run            
count is 1
count is 1
结果显示无论子进程还是父进程,显示结果最终都为1,这个简单的可以说明fork创建的进程虽然代码段子进程与父进程共用,但是数据段并不共用,当父进程创建子进程时,同时将数据“复制”了一份给子进程。两个进程相互独立互不干扰。

那么将上面程序中的fork()换为vfork()代码如下:

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

再来观察程序运行结果:

[root@localhost fork]# gcc fork.c -o start
[root@localhost fork]# ./start 
count is 1
count is 2
结果显示

count 在数据上有了正常叠加,这说明vfork()创建的子进程父进程共享数据段与代码段,父进程创建子进程时不会将数据复制一份给子进程,而是两个进程共享数据段。这里为了简便没有区分父子进程,如果区分,显示结果将是子进程count结果为1,父进程打印结果为2。

除此之外这两个函数在进程执行顺序上有不同,fork()创建子进程后,子进程与父进程的执行顺序是随机的,而vfork()创建子进程后,父进程等待子进程执行完毕后,才来执行父进程。

注意:fork() vfork()两个函数运用时会发现,vfork创建进程结束时调用exit()函数,而不是return()返回值方式结束,若采用return()方式结束进程,运行程序时程序会发生段错误,导致程序不断执行无法正常结束,但是采用fork()创建进程,采用return方式结束却不会发生错误,这是为什么呢?return是语言级别的结束,exit是系统进程调用级别的结束,主函数执行return时会认为程序结束释放程序堆栈空间等数据,exit()函数结束进程,将相关信息返回OS供OS处理下一步任务,还是那一点,fork创建父子进程之后,两个进程完全独立,数据空间互不干扰,进程末尾return()返回以后,系统释放各自任务堆栈空间,父子进程正常结束,不会发生错误。但是vfork()不同,父子进程共享数据段代码段,执行时阻塞掉父进程先执行子进程,若子进程采用return结束进程,函数认为执行完毕,释放任务堆栈等信息,从而导致父进程进程运行参数被破坏,程序无法正常执行,导致段错误的产生(个人理解)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
fork和vforkLinux系统中用来创建进程的函数,它们的区别在于进程的创建和共享数据段的方式。当调用fork函数时,父进程会创建一个子进程,并且子进程会拷贝父进程的数据段。子进程在fork之后会执行父进程的代码,但是父子进程的执行顺序是不确定的。而当调用vfork函数时,父进程会创建一个子进程,但是子进程不会拷贝父进程的数据段,而是与父进程共享数据段。在vfork中,子进程会先运行,而父进程会挂起,直到子进程调用了exec或者exit函数,父进程才会被执行。 因此,fork适用于需要在子进程中修改数据的情况,而vfork适用于需要在子进程中立即执行一个新程序的情况。另外,vfork函数的性能比fork函数要好,因为vfork不需要完全拷贝父进程的数据段。然而,由于vfork与父进程共享数据段,所以需要注意在子进程中不要修改共享的数据,以免影响到父进程的执行。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [详解linuxfork、vfork、clone函数的区别](https://download.csdn.net/download/weixin_38509656/12844110)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [fork与vfork详解](https://blog.csdn.net/iteye_4389/article/details/82518147)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [fork/vfork详解](https://blog.csdn.net/weixin_36750623/article/details/83041030)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值