linux系统编程-进程2-vfork && exit

vfork() 是一个函数原型,用于创建一个新的子进程,与 fork() 类似。它的原型如下:

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

pid_t vfork(void);

vfork() 函数的返回值在不同情况下有不同的含义:

  • 如果 vfork() 返回值是负数,表示创建子进程失败,可能由于系统资源不足或其他错误。此时,可以通过查看 errno 变量获取具体的错误代码。

  • 如果 vfork() 返回值是0,表示当前代码正在执行的是子进程的上下文中。子进程可以继续执行自己的逻辑,例如调用 exec() 启动一个新程序或者使用 _exit() 终止自己。

  • 如果 vfork() 返回值大于0,表示当前代码正在执行的是父进程的上下文中。返回值是子进程的 PID(进程标识符),可以通过这个 PID 来区分父进程和子进程,并对它们进行不同的操作。

vfork() 函数通过创建一个新的子进程来实现,新的子进程几乎和父进程共享地址空间。与 fork() 不同的是,vfork() 在创建子进程时并不会复制父进程的地址空间,而是直接与父进程共享地址空间。

由于 vfork() 子进程与父进程共享地址空间,所以在子进程执行期间,父进程会被阻塞。子进程在 vfork() 返回后,可以使用 exec 函数族中的一个函数来加载另一个可执行程序,或者调用 _exit() 函数来终止自身。在子进程执行这些操作后,父进程恢复执行。

需要注意的是,由于 vfork() 的特殊性,它的使用方式要比 fork() 更加谨慎。通常情况下,建议使用 fork() 来创建子进程。

vfork() 的主要特点如下:

  1. 共享地址空间:子进程与父进程共享相同的地址空间,包括代码段、数据段和堆栈等,因此子进程可以直接访问父进程的变量和数据。
  2. 父进程挂起:在子进程执行期间,父进程会被挂起,直到子进程调用 _exit() 终止自己或者执行了一个新的程序(例如通过 exec()),父进程才会恢复运行。
  3. 不复制地址空间:与 fork() 不同,vfork() 并不会复制整个地址空间,而是与父进程共享同一份地址空间,因此在子进程中修改变量会影响到父进程。

由于 vfork() 子进程与父进程共享地址空间,因此可以显著减少资源的消耗和复制时间。但需要注意的是,在子进程执行期间,应该避免对共享数据进行修改,以免破坏父进程的状态。

一般情况下,我们通常使用 fork() 来创建新进程,因为它更加安全可靠。只有在确实需要在子进程中立即执行一个新的程序时,才会选择使用 vfork()

exit() 是一个函数,用于正常终止一个程序或进程。它的原型如下:

#include <stdlib.h>

void exit(int status);

exit() 函数接受一个整数参数 status,用于指定程序或进程的退出状态。根据惯例,返回值为 0 表示程序正常终止,非零值表示程序异常终止。

当调用 exit() 函数时,它会执行以下操作:

  1. 刷新标准 I/O 流(包括 stdout、stderr 等)。
  2. 调用在使用 atexit() 注册的回调函数(如果有的话),按照注册的相反顺序依次调用这些函数。
  3. 关闭打开的文件描述符(文件句柄)。

最后,exit() 将传递给它的 status 值返回给调用它的进程或操作系统。这个值可以被父进程通过 wait()waitpid() 等函数获取。

需要注意的是,调用 exit() 函数会立即终止当前进程,不会再执行之后的代码。

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

int main()
{
    pid_t pid;
    int cnt = 0;
    
    pid = vfork();  // 使用 vfork() 创建子进程,子进程与父进程共享地址空间
    
    if (pid > 0)  // 父进程逻辑
    {
        while (1) {
            printf("father, pid = %d\n", getpid());
            cnt++;
            sleep(3);
            if (cnt == 6)
                break;
        }
    }
    else if (pid == 0)  // 子进程逻辑
    {
        while (1) {
            printf("child, pid = %d\n", getpid());
            sleep(3);
            cnt++;
            if (cnt == 3) {
                exit(0);  // 子进程调用 exit() 终止自己
            }
        }
    }
    else  // vfork() 失败处理
    {
        perror("vfork");
        return 1;
    }

    return 0;
}

分析结果可知vfork() 在创建子进程时并不会复制父进程的地址空间,而是直接与父进程共享地址空间。当子进程调用exit(0)退出的时候cnt=3;回到父进程后从3开始继续++;

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MichstaBe#

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值