通过系统调用体验进程的生命周期

一、系统调用介绍:

        本章内容将会在Linux系统下,通过系统调用来体验进程的生命周期。由于涉及到一些系统调用,那么首先先解释一下所涉及的系统调用:

1.fork():

        fork()方法是用来创建一个进程的,fork()函数创建的进程为子进程,调用fork()函数的进程称父进程。调用fork()函数过后, 系统会创建一个与原进程几乎相同的进程(感觉就像是将父进程的程序代码复制了一份给子进程),然后父子进程都继续往下执行。
fork()函数调用成功后它能返回两个值,因为如果调用成功,父进程的代码就会复制给子进程,这样也就有了两个fork()函数,所以返回两个值。父进程的fork()函数返回值是子进程的pid, 子进程的fork()函数返回值是0。若进程创建失败,则原进程不会被复制, 返回值为-1。

2.wait():

        wait()是一个用于等待子进程结束并获取其退出状态的系统调用。它在操作系统中的作用非常重要,允许父进程控制子进程的执行,以及处理子进程的退出状态。

  1. 等待子进程结束:

    当调用 wait() 时,父进程会被阻塞,直到一个子进程结束。父进程将控制权交给操作系统,并在子进程结束后继续执行。

  2. 获取子进程的退出状态:

    通过 wait() 返回的子进程PID,可以获得子进程的退出状态信息,存储在 status 变量中。通常,可以使用宏来检查子进程的退出状态:

    • WIFEXITED(status):检查子进程是否正常退出,如果是正常退出则返回真(非零值)。
    • WEXITSTATUS(status):获取正常退出的子进程的退出码,这是一个整数值,通常用来指示子进程的执行结果。
    • 其他宏如 WIFSIGNALED 和 WTERMSIG 用于处理异常终止的情况。

 3.execlp():

        execlp()是一个用于在当前进程中执行新程序的系统调用,它会在系统的环境变量 PATH 中查找可执行文件。execlp() 允许在当前进程中执行新程序,方便地查找可执行文件,以及传递参数给新程序。这在创建新进程并执行外部命令时非常有用。

4.sleep():

        当调用 sleep(seconds) 时,当前进程会暂时挂起,不再执行任何代码,直到指定的秒数过去为止。这可以用来实现定时操作、等待一段时间后再继续执行等情况。sleep() 函数会休眠指定的秒数,并返回未休眠完的剩余秒数(如果有的话)。如果休眠时间已经耗尽,它会返回0。该系统调用会导致当前进程完全挂起,不会占用 CPU 资源。

5.exit():

   exit(int status) 是一个用于终止当前进程的函数。它用于通知操作系统当前进程已经完成,并且可以选择返回一个整数退出状态码。当调用 exit(status) 时,当前进程会被立即终止。这意味着进程的所有代码和资源都会被操作系统回收,包括打开的文件、分配的内存等。通过 status 参数,可以指定进程的退出状态,这个状态可以在其他程序或脚本中通过特殊变量来获取。这个状态码通常用于指示程序的执行结果,例如,0 表示成功,非零值表示错误或其他情况。

二、示例代码:

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

int main() {
    pid_t child_pid;

    // Fork一个新的进程
    child_pid = fork();

    if (child_pid == 0) {
        // 这是子进程
        printf("子进程: PID=%d\n", getpid());

        // 使用exec调用执行一个新的程序
        execlp("/bin/ls", "ls", NULL);

        // 如果exec失败,会继续执行以下代码
        perror("exec");
        return 1;
    } else if (child_pid > 0) {
        // 这是父进程
        printf("父进程: PID=%d, 子进程的PID=%d\n", getpid(), child_pid);

        // 等待子进程结束
        int status;
        wait(&status);
        if (WIFEXITED(status)) {
            printf("子进程正常退出,退出码:%d\n", WEXITSTATUS(status));
        }
    } else {
        perror("fork");
        return 1;
    }

    // 父进程继续执行
    printf("父进程继续执行\n");

    // 等待一段时间
    sleep(2);

    // 退出进程
    exit(0);

    // 这里的代码不会被执行
    printf("这段代码不会被执行\n");
}

结果:

        接下来我们来分析一下这段代码,首先父进程fork了一个子进程,fork的返回值大于0,表示当前的进程为父进程,因此,代码就执行到了else if代码块中,父进程先打印信息(结果中的第一行),接下来执行wait()方法,父进程阻塞了,并且等待子进程执行完毕。用于在子进程中,fork的返回值为0,子进程就开始进入if代码块中执行了,子进程先打印自己的PID,执行了ls指令后(结果中第二,三,四行),会转到父进程的wait()代码处,父进程会继续执行(结果中第五、六行)。

        OK,通过以上的分析,相信大家对于进程的生命周期也有了一定的了解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值