admin管理员组

文章数量:1028075

【进程控制】

1. 写时拷贝

父进程创建了子进程,子进程的PCB是拷贝的父进程的PCB,内容一致。并且数据段,代码段,子进程是与父进程共享的(此时权限会被设为只读),当子进程要对其进行修改,此时会发生写时拷贝,将子进程要修改的数据,拷贝一份,单独交给子进程(这一部分权限可写,可读)。

2. 进程终止

2.1 从main返回

2.2 调用exit

2.3 _exit

3. 进程等待

waitwaitpid 是 Unix/Linux 系统中用于处理子进程状态变化的系统调用,通常在 C 或 C++ 编程里使用。下面为你详细介绍:

3.1 wait 函数

  • 函数原型
代码语言:javascript代码运行次数:0运行复制
#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *status);
  • 功能wait 函数会让调用进程阻塞,直到它的任意一个子进程终止。若子进程已经终止,wait 会立即返回。返回值是终止子进程的进程 ID,若出错则返回 -1。
  • 参数status 是一个整型指针,用于存储子进程的终止状态。若不关心终止状态,可将其设为 NULL
  • 示例代码
代码语言:javascript代码运行次数:0运行复制
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main() {
    pid_t pid = fork();

    if (pid < 0) {
        perror("fork");
        return 1;
    } else if (pid == 0) {
        // 子进程
        printf("Child process is running.\n");
        sleep(2);
        printf("Child process is exiting.\n");
        exit(0);
    } else {
        // 父进程
        int status;
        pid_t child_pid = wait(&status);
        if (child_pid > 0) {
            if (WIFEXITED(status)) {
                printf("Child process %d exited normally with status %d.\n", child_pid, WEXITSTATUS(status));
            } else if (WIFSIGNALED(status)) {
                printf("Child process %d was terminated by signal %d.\n", child_pid, WTERMSIG(status));
            }
        }
    }

    return 0;
}

3.2 waitpid 函数

  • 函数原型
代码语言:javascript代码运行次数:0运行复制
#include <sys/types.h>
#include <sys/wait.h>

pid_t waitpid(pid_t pid, int *status, int options);
  • 功能waitpid 函数的功能与 wait 类似,不过它可以指定等待某个特定的子进程,还能通过 options 参数来控制等待行为。返回值是终止子进程的进程 ID,若指定 WNOHANG 且没有子进程终止则返回 0,若出错则返回 -1。
  • 参数
    • pid:用于指定要等待的子进程的进程 ID。若 pid > 0,则等待指定进程 ID 的子进程;若 pid == -1,则等待任意子进程,等同于 wait;若 pid == 0,则等待与调用进程在同一进程组的任意子进程;若 pid < -1,则等待进程组 ID 等于 pid 绝对值的任意子进程。
    • status:和 wait 中的 status 作用相同,用于存储子进程的终止状态。
    • options:是一个位掩码,可使用 WNOHANGwaitpid 非阻塞地返回,即若没有子进程终止则立即返回 0;还可使用 WUNTRACED 来关注因收到信号而停止的子进程。
  • 示例代码
代码语言:javascript代码运行次数:0运行复制
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main() {
    pid_t pid = fork();

    if (pid < 0) {
        perror("fork");
        return 1;
    } else if (pid == 0) {
        // 子进程
        printf("Child process is running.\n");
        sleep(2);
        printf("Child process is exiting.\n");
        exit(0);
    } else {
        // 父进程
        int status;
        pid_t child_pid = waitpid(pid, &status, WNOHANG);
        if (child_pid == 0) {
            printf("No child process has exited yet.\n");
        } else if (child_pid > 0) {
            if (WIFEXITED(status)) {
                printf("Child process %d exited normally with status %d.\n", child_pid, WEXITSTATUS(status));
            } else if (WIFSIGNALED(status)) {
                printf("Child process %d was terminated by signal %d.\n", child_pid, WTERMSIG(status));
            }
        }
    }

    return 0;
}

3.3 区别总结

  • 灵活性wait 只能等待任意子进程终止,而 waitpid 能指定等待某个特定的子进程,并且可以控制等待行为,如非阻塞等待。
  • 阻塞特性wait 是阻塞调用,会一直等待直到有子进程终止;waitpid 可通过 WNOHANG 选项实现非阻塞调用。

4. 进程替换

替换原理 用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。

替换函数

4.1 execl

4.2 execlp

4.3 execle

4.4 execv

4.5 execvp

4.6 execvpe

execvpe 是 Unix/Linux 系统里 exec 函数族中的一员,该函数族的作用是在当前进程的上下文中执行新程序,替换当前进程的映像。下面详细介绍 execvpe 函数。

4.6.1 函数原型
代码语言:javascript代码运行次数:0运行复制
#include <unistd.h>
#include <stdlib.h>

int execvpe(const char *file, char *const argv[], char *const envp[]);
4.6.2 参数说明
  • file:指向要执行的程序文件名的指针。此文件名无需是完整路径,execvpe 会依据 PATH 环境变量来查找该程序。
  • argv:指向参数数组的指针,该数组里的每个元素都是一个指向字符串的指针,代表传递给新程序的参数。数组的第一个元素通常是新程序的名称,最后一个元素必须为 NULL,以此标记参数列表的结束。
  • envp:指向环境变量数组的指针。数组中的每个元素都是形如 name=value 的字符串,用于为新程序设置环境变量。
4.6.3 功能说明

execvpe 函数会用指定的程序替换当前进程的映像。若调用成功,它不会返回;只有在调用失败时,才会返回 -1,并设置相应的错误码。

4.6.4 示例代码
代码语言:javascript代码运行次数:0运行复制
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main() {
    // 定义要执行的程序文件名
    const char *file = "ls";

    // 定义传递给程序的参数数组
    char *argv[] = {
        "ls",
        "-l",
        NULL
    };

    // 定义环境变量数组
    char *envp[] = {
        "PATH=/bin:/usr/bin",
        "HOME=/home/user",
        NULL
    };

    // 调用 execvpe 函数执行新程序
    int result = execvpe(file, argv, envp);

    // 如果 execvpe 调用失败,会执行到这里
    if (result == -1) {
        perror("execvpe");
        return 1;
    }

    return 0;
}
4.6.5 代码解释
  • 在这个示例中,我们运用 execvpe 函数执行了 ls 程序,并且传递了 -l 参数。
  • 为新程序设置了两个环境变量 PATHHOME
  • execvpe 调用成功,当前进程会被 ls 程序替代,输出文件列表。若调用失败,则会输出错误信息。
4.6.6 注意事项
  • 由于 execvpe 调用成功后不会返回,所以调用之前的代码会被执行,而调用之后的代码只有在调用失败时才会执行。
  • file 参数不是完整路径,execvpe 会依据 envp 数组里的 PATH 环境变量查找程序。若 envp 中未包含 PATH,则使用当前进程的 PATH 环境变量。
  • 传递给新程序的参数列表和环境变量数组都必须以 NULL 结尾。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2025-04-27,如有侵权请联系 cloudcommunity@tencent 删除指针程序函数进程数组

【进程控制】

1. 写时拷贝

父进程创建了子进程,子进程的PCB是拷贝的父进程的PCB,内容一致。并且数据段,代码段,子进程是与父进程共享的(此时权限会被设为只读),当子进程要对其进行修改,此时会发生写时拷贝,将子进程要修改的数据,拷贝一份,单独交给子进程(这一部分权限可写,可读)。

2. 进程终止

2.1 从main返回

2.2 调用exit

2.3 _exit

3. 进程等待

waitwaitpid 是 Unix/Linux 系统中用于处理子进程状态变化的系统调用,通常在 C 或 C++ 编程里使用。下面为你详细介绍:

3.1 wait 函数

  • 函数原型
代码语言:javascript代码运行次数:0运行复制
#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *status);
  • 功能wait 函数会让调用进程阻塞,直到它的任意一个子进程终止。若子进程已经终止,wait 会立即返回。返回值是终止子进程的进程 ID,若出错则返回 -1。
  • 参数status 是一个整型指针,用于存储子进程的终止状态。若不关心终止状态,可将其设为 NULL
  • 示例代码
代码语言:javascript代码运行次数:0运行复制
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main() {
    pid_t pid = fork();

    if (pid < 0) {
        perror("fork");
        return 1;
    } else if (pid == 0) {
        // 子进程
        printf("Child process is running.\n");
        sleep(2);
        printf("Child process is exiting.\n");
        exit(0);
    } else {
        // 父进程
        int status;
        pid_t child_pid = wait(&status);
        if (child_pid > 0) {
            if (WIFEXITED(status)) {
                printf("Child process %d exited normally with status %d.\n", child_pid, WEXITSTATUS(status));
            } else if (WIFSIGNALED(status)) {
                printf("Child process %d was terminated by signal %d.\n", child_pid, WTERMSIG(status));
            }
        }
    }

    return 0;
}

3.2 waitpid 函数

  • 函数原型
代码语言:javascript代码运行次数:0运行复制
#include <sys/types.h>
#include <sys/wait.h>

pid_t waitpid(pid_t pid, int *status, int options);
  • 功能waitpid 函数的功能与 wait 类似,不过它可以指定等待某个特定的子进程,还能通过 options 参数来控制等待行为。返回值是终止子进程的进程 ID,若指定 WNOHANG 且没有子进程终止则返回 0,若出错则返回 -1。
  • 参数
    • pid:用于指定要等待的子进程的进程 ID。若 pid > 0,则等待指定进程 ID 的子进程;若 pid == -1,则等待任意子进程,等同于 wait;若 pid == 0,则等待与调用进程在同一进程组的任意子进程;若 pid < -1,则等待进程组 ID 等于 pid 绝对值的任意子进程。
    • status:和 wait 中的 status 作用相同,用于存储子进程的终止状态。
    • options:是一个位掩码,可使用 WNOHANGwaitpid 非阻塞地返回,即若没有子进程终止则立即返回 0;还可使用 WUNTRACED 来关注因收到信号而停止的子进程。
  • 示例代码
代码语言:javascript代码运行次数:0运行复制
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main() {
    pid_t pid = fork();

    if (pid < 0) {
        perror("fork");
        return 1;
    } else if (pid == 0) {
        // 子进程
        printf("Child process is running.\n");
        sleep(2);
        printf("Child process is exiting.\n");
        exit(0);
    } else {
        // 父进程
        int status;
        pid_t child_pid = waitpid(pid, &status, WNOHANG);
        if (child_pid == 0) {
            printf("No child process has exited yet.\n");
        } else if (child_pid > 0) {
            if (WIFEXITED(status)) {
                printf("Child process %d exited normally with status %d.\n", child_pid, WEXITSTATUS(status));
            } else if (WIFSIGNALED(status)) {
                printf("Child process %d was terminated by signal %d.\n", child_pid, WTERMSIG(status));
            }
        }
    }

    return 0;
}

3.3 区别总结

  • 灵活性wait 只能等待任意子进程终止,而 waitpid 能指定等待某个特定的子进程,并且可以控制等待行为,如非阻塞等待。
  • 阻塞特性wait 是阻塞调用,会一直等待直到有子进程终止;waitpid 可通过 WNOHANG 选项实现非阻塞调用。

4. 进程替换

替换原理 用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。

替换函数

4.1 execl

4.2 execlp

4.3 execle

4.4 execv

4.5 execvp

4.6 execvpe

execvpe 是 Unix/Linux 系统里 exec 函数族中的一员,该函数族的作用是在当前进程的上下文中执行新程序,替换当前进程的映像。下面详细介绍 execvpe 函数。

4.6.1 函数原型
代码语言:javascript代码运行次数:0运行复制
#include <unistd.h>
#include <stdlib.h>

int execvpe(const char *file, char *const argv[], char *const envp[]);
4.6.2 参数说明
  • file:指向要执行的程序文件名的指针。此文件名无需是完整路径,execvpe 会依据 PATH 环境变量来查找该程序。
  • argv:指向参数数组的指针,该数组里的每个元素都是一个指向字符串的指针,代表传递给新程序的参数。数组的第一个元素通常是新程序的名称,最后一个元素必须为 NULL,以此标记参数列表的结束。
  • envp:指向环境变量数组的指针。数组中的每个元素都是形如 name=value 的字符串,用于为新程序设置环境变量。
4.6.3 功能说明

execvpe 函数会用指定的程序替换当前进程的映像。若调用成功,它不会返回;只有在调用失败时,才会返回 -1,并设置相应的错误码。

4.6.4 示例代码
代码语言:javascript代码运行次数:0运行复制
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main() {
    // 定义要执行的程序文件名
    const char *file = "ls";

    // 定义传递给程序的参数数组
    char *argv[] = {
        "ls",
        "-l",
        NULL
    };

    // 定义环境变量数组
    char *envp[] = {
        "PATH=/bin:/usr/bin",
        "HOME=/home/user",
        NULL
    };

    // 调用 execvpe 函数执行新程序
    int result = execvpe(file, argv, envp);

    // 如果 execvpe 调用失败,会执行到这里
    if (result == -1) {
        perror("execvpe");
        return 1;
    }

    return 0;
}
4.6.5 代码解释
  • 在这个示例中,我们运用 execvpe 函数执行了 ls 程序,并且传递了 -l 参数。
  • 为新程序设置了两个环境变量 PATHHOME
  • execvpe 调用成功,当前进程会被 ls 程序替代,输出文件列表。若调用失败,则会输出错误信息。
4.6.6 注意事项
  • 由于 execvpe 调用成功后不会返回,所以调用之前的代码会被执行,而调用之后的代码只有在调用失败时才会执行。
  • file 参数不是完整路径,execvpe 会依据 envp 数组里的 PATH 环境变量查找程序。若 envp 中未包含 PATH,则使用当前进程的 PATH 环境变量。
  • 传递给新程序的参数列表和环境变量数组都必须以 NULL 结尾。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2025-04-27,如有侵权请联系 cloudcommunity@tencent 删除指针程序函数进程数组

本文标签: 进程控制