Linux系统编程(vfork和fork)

简介: Linux系统编程(vfork和fork)

前言

本篇文章讲解vfork和fork创建进程的区别。

一、vfork讲解

vfork 是一个在类Unix操作系统中的系统调用,它创建一个新进程,且该进程与父进程共享内存空间。Vfork系统调用的目的是为了在子进程中执行一个新的程序,通常是通过调用exec系列函数来实现。

vfork 的函数原型如下:

#include <unistd.h>
pid_t vfork(void);

vfork 函数返回一个正值给父进程,返回0给子进程,或者返回一个负值表示创建失败。父进程和子进程之间的主要区别在于在子进程调用 exec 函数之前,它会挂起父进程的执行。这样,子进程可以直接执行一个新的程序,而不需要复制父进程的地址空间

使用 vfork 创建的子进程与父进程共享同一个地址空间,这意味着子进程可以直接访问父进程的变量、函数和堆栈等。由于父进程被挂起,直到子进程调用 exec 函数或 _exit 函数终止,父进程在子进程运行期间是阻塞的。

需要注意的是,由于子进程与父进程共享同一份地址空间,因此在子进程中修改父进程的变量和数据可能会导致不可预期的行为,因此要小心使用。一般来说,vfork 主要用于创建一个新进程,并在该进程中立即调用 exec 函数来加载一个新程序。这样可以避免复制父进程的大型地址空间,提高创建子进程的效率。

总结一下,vfork 是一个在类Unix操作系统中的系统调用,用于创建一个新进程,并与父进程共享地址空间。子进程通过调用 exec 函数来执行一个新程序。父进程在子进程调用 exec 函数之前会被挂起,直到子进程结束或调用 _exit 函数。使用 vfork 可以避免复制父进程的地址空间,从而提高创建子进程的效率。但要小心在子进程中修改父进程的变量和数据,以避免不可预期的结果。

二、vfork使用

这里使用vfork创建了进程:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#define EXE "test"
int main(void)
{
    int pid = 0;
    char* argv[3] = {EXE, "world", NULL};
    printf("begin\n");
    printf("now pid : %d\n", getpid());
    if((pid = vfork()) != 0)
    {
        //父进程
    }
    else
    {
        //子进程
        execve(EXE, argv, argv);
        _exit(0);
    }  
    printf("end\n");
    return 0;
}

三、exit和_exit

1.exit和_exit对比

_exit 和 exit 是两个在C语言中常用的函数,用于进程的终止。它们的主要区别在于以下几点:

头文件不同:_exit 函数在 <unistd.h> 头文件中声明,而 exit 函数在 <stdlib.h> 头文件中声明。

执行清理函数的行为:_exit 函数会直接终止进程,不会执行任何清理操作,包括清理注册的函数(比如通过 atexit 注册的函数)。而 exit 函数在终止进程之前会执行这些清理函数,包括文件的关闭、内存的释放、缓冲区的刷新等。这使得 exit 函数更适合用于正常的进程终止,可以确保资源被正确释放。

返回值的意义不同:_exit 函数的返回值作为进程的终止状态,可以被父进程通过 wait 系统调用获取到。而 exit 函数的返回值通常被忽略,它会被用作状态码传递给父进程,父进程可以通过相关的方式读取该状态码,例如在 shell 中使用 $? 来获取。

缓冲区刷新:_exit 函数不会刷新缓冲区,这意味着通过 printf 等函数输出的内容可能不会立即显示出来。而 exit 函数会刷新缓冲区,确保所有的输出都被写入对应的文件或在屏幕上显示出来。

2.在vfork中的使用

vfork 创建的子进程通常只能调用 _exit 函数,而不应该调用 exit 函数。这是因为 vfork 在创建子进程时会共享父进程的地址空间,包括栈、堆和全局变量等。子进程在调用 exec 或 _exit 函数之前不能修改父进程地址空间中的任何数据,否则会导致不可预测的行为。

exit 函数在执行时会进行一系列的清理工作,包括关闭文件描述符、释放动态分配的内存、刷新缓冲区等。这些操作可能会影响到父进程状态和资源的正确释放,而且在共享地址空间的情况下,子进程对这些资源的修改会影响到父进程。

为了避免这种混乱和不确定性,vfork 子进程应该尽量快速地调用 _exit 函数来终止自己。_exit 函数直接终止进程,不进行任何清理,并且不会影响到父进程的状态或资源。

总结起来,vfork 创建的子进程应该使用 _exit 函数来终止自己,而不应该调用 exit 函数。这样可以避免对父进程地址空间中的数据和资源产生不可预测的影响,确保子进程的终止操作不会影响到父进程。

四、vfork和fork区别

vfork 和 fork 是两个在类Unix操作系统中常用的系统调用,用于创建新的进程。它们之间的主要区别如下:

1.地址空间的复制方式:vfork 创建的子进程与父进程共享地址空间,而 fork 创建的子进程会复制父进程的地址空间。这意味着在 vfork 的子进程中,对地址空间的修改会影响到父进程,而在 fork 的子进程中,修改则是独立的。

2.父进程的行为:vfork 创建的子进程会共享父进程的资源(如文件描述符、堆栈等),并且父进程会在子进程调用 exec 或 _exit 函数之前挂起。而 fork 创建的子进程会复制父进程的资源,并且父进程和子进程可以同时运行。

3.子进程的返回值:在 vfork 中,子进程的返回值是通过函数返回值方式返回的,即在子进程中直接返回,而在父进程中可以通过获取子进程的返回值。而在 fork 中,子进程的返回值为0,父进程中可以通过获取子进程的PID来区分父进程与子进程。

4.父进程的阻塞:在 vfork 中,父进程会在子进程调用 exec 或 _exit 函数之前一直被阻塞,直到子进程终止或执行了新的程序。而在 fork 中,父进程和子进程可以并发执行,它们的执行顺序取决于操作系统的调度算法。

综上所述,主要的区别在于地址空间的复制方式、父进程的行为、子进程的返回值以及父进程的阻塞方式。vfork 创建的子进程与父进程共享地址空间,并且父进程会被阻塞;fork 创建的子进程复制父进程的地址空间,父子进程可以同时执行。选择使用哪个系统调用取决于具体的需求和场景。一般而言,fork 是更常用的方式,而 vfork 则用于特定的情况,例如在子进程中立即执行 exec 函数。

总结

本篇文章讲解了vfork的具体操作和内部含义,并且将vfork和fork进行了对比。


相关文章
|
7天前
|
Linux 应用服务中间件 Shell
linux系统服务二!
本文详细介绍了Linux系统的启动流程,包括CentOS 7的具体启动步骤,从BIOS自检到加载内核、启动systemd程序等。同时,文章还对比了CentOS 6和CentOS 7的启动流程,分析了启动过程中的耗时情况。接着,文章讲解了Linux的运行级别及其管理命令,systemd的基本概念、优势及常用命令,并提供了自定义systemd启动文件的示例。最后,文章介绍了单用户模式和救援模式的使用方法,包括如何找回忘记的密码和修复启动故障。
27 5
linux系统服务二!
|
7天前
|
Linux 应用服务中间件 Shell
linux系统服务!!!
本文详细介绍了Linux系统(以CentOS7为例)的启动流程,包括BIOS自检、读取MBR信息、加载Grub菜单、加载内核及驱动程序、启动systemd程序加载必要文件等五个主要步骤。同时,文章还对比了CentOS6和CentOS7的启动流程图,并分析了启动流程的耗时。此外,文中还讲解了Linux的运行级别、systemd的基本概念及其优势,以及如何使用systemd管理服务。最后,文章提供了单用户模式和救援模式的实战案例,帮助读者理解如何在系统启动出现问题时进行修复。
26 3
linux系统服务!!!
|
1天前
|
机器学习/深度学习 自然语言处理 Linux
Linux 中的机器学习:Whisper——自动语音识别系统
本文介绍了先进的自动语音识别系统 Whisper 在 Linux 环境中的应用。Whisper 基于深度学习和神经网络技术,支持多语言识别,具有高准确性和实时处理能力。文章详细讲解了在 Linux 中安装、配置和使用 Whisper 的步骤,以及其在语音助手、语音识别软件等领域的应用场景。
12 5
|
1天前
|
缓存 运维 监控
【运维必备知识】Linux系统平均负载与top、uptime命令详解
系统平均负载是衡量Linux服务器性能的关键指标之一。通过使用 `top`和 `uptime`命令,可以实时监控系统的负载情况,帮助运维人员及时发现并解决潜在问题。理解这些工具的输出和意义是确保系统稳定运行的基础。希望本文对Linux系统平均负载及相关命令的详细解析能帮助您更好地进行系统运维和性能优化。
12 3
|
1天前
|
监控 网络协议 算法
Linux内核优化:提升系统性能与稳定性的策略####
本文深入探讨了Linux操作系统内核的优化策略,旨在通过一系列技术手段和最佳实践,显著提升系统的性能、响应速度及稳定性。文章首先概述了Linux内核的核心组件及其在系统中的作用,随后详细阐述了内存管理、进程调度、文件系统优化、网络栈调整及并发控制等关键领域的优化方法。通过实际案例分析,展示了这些优化措施如何有效减少延迟、提高吞吐量,并增强系统的整体健壮性。最终,文章强调了持续监控、定期更新及合理配置对于维持Linux系统长期高效运行的重要性。 ####
|
7天前
|
网络协议 Linux
linux系统重要文件目录
本文介绍了Linux系统中的重要目录及其历史背景,包括根目录、/usr、/etc、/var/log和/proc等目录的结构和功能。其中,/etc目录下包含了许多关键配置文件,如网卡配置、DNS解析、主机名设置等。文章还详细解释了各目录和文件的作用,帮助读者更好地理解和管理Linux系统。
25 2
|
8天前
|
Ubuntu Linux Shell
Linux 系统中的代码类型或脚本类型内容
在 Linux 系统中,代码类型多样,包括 Shell 脚本、配置文件、网络配置、命令行工具和 Cron 定时任务。这些代码类型广泛应用于系统管理、自动化操作、网络配置和定期任务,掌握它们能显著提高系统管理和开发的效率。
|
11天前
|
关系型数据库 MySQL Linux
Linux系统如何设置自启动服务在MySQL数据库启动后执行?
【10月更文挑战第25天】Linux系统如何设置自启动服务在MySQL数据库启动后执行?
59 3
|
12天前
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
14天前
|
存储 安全 关系型数据库
Linux系统在服务器领域的应用与优势###
本文深入探讨了Linux操作系统在服务器领域的广泛应用及其显著优势。通过分析其开源性、安全性、稳定性和高效性,揭示了为何Linux成为众多企业和开发者的首选服务器操作系统。文章还列举了Linux在服务器管理、性能优化和社区支持等方面的具体优势,为读者提供了全面而深入的理解。 ###
下一篇
无影云桌面