Linux之进程等待(wait,waitpid,WIFEXITED(),WEXITATATUS(),WNOHA)和进程替换(execl*)

个人主页点我进入主页

专栏分类:C语言初阶  C语言进阶  数据结构初阶    Linux    C++初阶    算法

欢迎大家点赞,评论,收藏。

一起努力,一起奔赴大厂

目录

一.进程等待

1.1进程等待引入

1.2如何等待(wait/waitpid)(等待是必须的,子进程的退出状态是不必须的)

1.2.1wait函数

 1.2.2waitpid函数位操作获取退出信息

1.2.3waipid函数宏获取退出信息WEXITSTATUS(status)  WIFWEXITED(status)

1.2.4非阻塞等待以及非阻塞轮询 WNOHANG

二.进程替换

2.1execl函数

 2.2execlp函数

 2.3execv函数

2,4execvp函数

2.5execvpe函数

2.6替换原理 


一.进程等待

1.1进程等待引入

        在一般情况下,父进程需要等待子进程,进程退出时,父进程不管不顾会造成子进程进入僵尸状态。  进程等待有什么作用呢?父进程通过进程等待,解决子进程僵尸问题,一旦子进程进入僵尸状态kill-9也不能将它回收,因此父进程等待可以回收资源,进程等待也可以获取子进程的退出信息,知道子进程是怎样退出的。

1.2如何等待(wait/waitpid)(等待是必须的,子进程的退出状态是不必须的)

1.2.1wait函数

我们先看下面代码

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

void RunChild()
{
    int cut=5;
    while(cut--)
    {
        printf("I am child ,pid=%d,ppid=%d\n",getpid(),getppid());
        sleep(1);
    }

}
int main()
{
    printf("I am father ,pid=%d,ppid=%d\n",getpid(),getppid());
    pid_t id=fork();
    if(id==0)
    {
        RunChild();
        printf("child quit...\n");
        exit(0);
    }
    pid_t rid=wait(NULL);
    if(rid>0)
    {
        printf("wait success,rid=%d\n",rid);
    }
} 

 我们运行后可以看到

        先执行程序,进入子进程和父进程同时运行,父进程先等待子进程,子进程运行,运行完后rid返回子进程的pid,然后再继续运行父进程。当我们再父进程开始时sleep(10),可以看到子进程进入僵尸状态

 1.2.2waitpid函数位操作获取退出信息

我们先看waitpid函数的参数<

<think>嗯,用户之前已经问过关于execl在Ubuntu中的用法,现在他们进一步询问如何结合fork来创建进程,并用execl替换进程的内容。首先,我需要确定用户的需求是什么。看起来他们可能正在学习进程管理,或者是想在实际项目中创建子进程来执行不同的程序。 用户的问题涉及forkexecl的结合使用,这在Unix-like系统中是很常见的模式。我需要先回顾fork的作用,它创建了一个子进程,复制父进程的内存空间。然后子进程调用execl来加载新的程序,替换当前的进程映像。这里需要注意的是,fork之后,子进程进程会并行执行,但通常父进程等待进程结束,以避免僵尸进程。 接下来,我需要考虑如何组织回答结构。用户之前的回答已经分步骤详细讲解了execl的用法,所以这次应该延续类似的风格,但重点放在forkexecl的组合使用上。可能需要包括代码示例,展示如何正确使用这两个函数,并解释每一步的作用。 还要注意用户可能的疑问点,比如为什么fork之后要用exec,或者如何处理可能的错误。例如,在fork之后,子进程中调用execl失败时应该退出,否则会继续执行父进程的代码,这可能会导致问题。此外,父进程需要调用wait来回收子进程的资源,防止僵尸进程的产生。 另外,用户可能需要了解不同exec函数之间的区别,比如execlexecv,但根据问题,这次主要集中在execl上。但或许可以简要提到其他变体,以便用户扩展知识。 在解释代码时,应该逐行分析,特别是fork的返回值处理,子进程进程的不同路径。同时强调路径必须是绝对路径,否则execl可能找不到可执行文件,导致失败。 最后,需要提醒用户进行错误处理,检查execl的返回值,并在失败时输出错误信息,使用perror或strerror(errno)来帮助调试。 可能还需要提到一些常见问题,比如忘记在参数列表末尾添加NULL,或者错误地使用相对路径,导致execl执行失败。此外,如果用户是在多线程环境中使用fork,可能会有其他注意事项,但这个问题可能超出了当前的范围,暂时不需要深入。 总结起来,回答需要结构清晰,分步骤说明forkexecl的使用流程,提供可编译的代码示例,并解释每个关键点,确保用户能够理解并正确应用这两个系统调用。</think>以下是结合 `fork()` `execl()` 在 Ubuntu 中创建子进程替换程序的详细步骤说明: --- ### 一、原理说明 1. **`fork()`**:创建子进程(复制父进程内存空间) 2. **`execl()`**:在子进程中加载新程序(覆盖原有内存) 3. **典型模式**:父进程管理,子进程执行新任务 --- ### 二、完整代码示例 ```c #include <stdio.h> #include <unistd.h> #include <sys/wait.h> #include <stdlib.h> int main() { pid_t pid = fork(); if (pid == -1) { perror("fork 失败"); exit(EXIT_FAILURE); } else if (pid == 0) { // 子进程代码区 printf("子进程 PID: %d 启动\n", getpid()); // 执行 /bin/ls -l execl("/bin/ls", "ls", "-l", NULL); // 只有 execl 失败才会执行到这里 perror("execl 失败"); exit(EXIT_FAILURE); } else { // 父进程代码区 printf("父进程 PID: %d 等待进程\n", getpid()); int status; waitpid(pid, &status, 0); // 等待进程结束 if (WIFEXITED(status)) { printf("子进程退出码: %d\n", WEXITSTATUS(status)); } } return 0; } ``` --- ### 三、关键步骤分解 #### 步骤 1:创建子进程 ```c pid_t pid = fork(); ``` - **返回值**: - `-1`:创建失败 - `0`:子进程执行区 - `>0`:父进程获得子进程PID #### 步骤 2:子进程执行替换 ```c execl("/bin/ls", "ls", "-l", NULL); ``` - **重要细节**: - 第一个参数必须是**绝对路径** - 参数列表必须以 `NULL` 结尾 - 如果执行失败会继续运行子进程代码 #### 步骤 3:父进程回收资源 ```c waitpid(pid, &status, 0); ``` - 防止产生僵尸进程(zombie process) - `WEXITSTATUS(status)` 获取子进程退出码 --- ### 四、执行流程演示 ```bash # 编译程序 gcc demo.c -o fork_execl_demo # 运行程序 ./fork_execl_demo # 典型输出: # 父进程 PID: 1234 等待进程 # 子进程 PID: 1235 启动 # [ls -l 的输出内容] # 子进程退出码: 0 ``` --- ### 五、常见问题处理 #### 问题 1:`execl` 参数错误 **错误代码**: ```c execl("ls", "ls", "-l", NULL); // 缺少绝对路径 ``` **解决方案**: ```c execl("/bin/ls", "ls", "-l", NULL); // 正确写法 ``` #### 问题 2:忘记调用 `wait()` **后果**: - 子进程结束后变成僵尸进程 **解决方法**: ```c // 父进程添加等待 waitpid(pid, &status, 0); ``` --- ### 六、扩展应用场景 1. **执行脚本**: ```c execl("/usr/bin/python3", "python3", "script.py", NULL); ``` 2. **带参数的程序**: ```c execl("/usr/bin/gcc", "gcc", "-o", "demo", "demo.c", NULL); ``` 3. **结合环境变量**(使用 `execle`): ```c char *env[] = {"PATH=/usr/local/bin", NULL}; execle("/app/myprogram", "myprogram", NULL, env); ``` --- ### 七、函数族对比 | 组合场景 | 推荐函数 | |-----------------------|---------------------| | 需要环境变量控制 | `fork()` + `execle` | | 参数数量动态变化 | `fork()` + `execv` | | 需要搜索 PATH 的路径 | `fork()` + `execlp` | --- 通过这种模式,您可以安全地在 Linux 系统中实现多进程任务分发。建议通过 `man 2 fork` `man 3 exec` 查看完整文档。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

steventom

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

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

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

打赏作者

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

抵扣说明:

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

余额充值