• linux 基础,你掌握了几个?


    86479b736688f41dcf6e0136c92a6b96.png

    点击蓝字 关注我们

    c29364f22a5fc75635edd2a34e33a498.png

    linux 基础,你掌握了几个?今天,我邀请了蓝桥云课合作作者——跑不了的你,给大家整理了 linux 基础——进程的退出及资源回收~希望对大家有帮助!(记得注意文末教育优惠哦~)

    41bd004542c3493204900669217dbca0.png

    进程的退出

    returen 和 exit,return 只是函数的返回,而 exit 却是进程的结束。

    void exit(int status);

    1. #include <stdlib.h>
    2. void exit(int status);
    3. 功能:终止进程
    4. 参数:
    5. status:退出状态码。status&0377的值给父进程。
    6. 返回值:
    7. 永远不返回。

    代码示例

    • test.c

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. int main(void){
    4. getchar();
    5. exit(-1);
    6. }
    • 执行结果

    8fce68633c6566e7f6b48d65ae44dd9d.png

    注册进程结束调用函数

    在进程结束前,可以注册一些函数给进程,在进程结束时会自动调用这些被注册的函数。

    on_exit(3)

    1. #include <stdlib.h>
    2. int on_exit(void (*function)(int , void *), void *arg);
    3. 功能:注册一个函数给进程,在进程终止的时候调用该函数
    4. 参数:
    5. function:指定退出函数的名字
    6. void (*function)(int , void *)
    7. arg:指定退出函数的第二个参数
    8. 返回值:
    9. 0 成功
    10. 0   错误

    代码示例(on_exit)

    • on_exit.c

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. void doit(int n,void *arg){
    4. printf("n=%d\targ:%s\n",\
    5. n,(char *)arg);
    6. return;
    7. }
    8. int main(void){
    9. //向进程注册退出函数
    10. on_exit(doit,"beijing");
    11. getchar();
    12. exit(3);
    13. }
    • 执行结果

    c08a2bc1d1e0278c786d049fe3ed2f59.png

    atexit

    atexit(3)

    1. #include <stdlib.h>
    2. int atexit(void (*function)(void));
    3. 功能:注册一个函数给进程,在进程终止的时候调用该函数
    4. 参数:
    5. function:指定了要注册的函数的名字
    6. 返回值:
    7. 0 成功
    8. 0 错误

    代码示例(atexit)

    • atexit.c

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. //注册给进程的退出函数
    4. void doit(void){
    5. printf("hahha....\n");
    6. return;
    7. }
    8. int main(void){
    9. //向进程注册一个退出处理函数
    10. atexit(doit);
    11. getchar();
    12. return 0;
    13. }
    • 执行结果

    91b55aec148f0f30c38229c855cc4d21.png

    进程资源的回收

    在进程退出后,父进程会回收子进程的资源。


    使用 wait(2)、waitpid(2) 系统调用回收子进程的资源。


    如果父进程早于子进程结束,那么父进程的子进程的父亲就改变成为 init 进程,这种进程被成为孤儿进程。


    代码示例

    • lonely.c

    1. #include <stdio.h>
    2. #include <unistd.h>
    3. #include <stdlib.h>
    4. int main(void){
    5. pid_t pid;
    6. //创建子进程
    7. pid=fork();
    8. if(pid==-1){
    9. perror("fork");
    10. return 1;
    11. }
    12. if(pid==0){//子进程的代码
    13. sleep(5);
    14. printf("child...\n");
    15. //getchar();
    16. exit(0);
    17. }else{//父进程的代码
    18. printf("parent...\n");
    19. exit(0);
    20. }
    21. return 0;
    22. }
    • 执行结果

    3174aef4f30417d4e223d23ee578db92.png

    wait 回收进程资源

    1. #include <sys/types.h>
    2. #include <sys/wait.h>
    3. pid_t wait(int *status);
    4. 功能:等待进程改变状态。
    5. 参数:
    6. status:退出状态码的地址。子进程的退出状态存放在这块地址空间里。可以使用一些宏检测退出原因。
    7. WIFEXITED(status) 如果正常死亡,返回真
    8. WEXITSTATUS(status) 返回子进程的退出状态和0377的与,那个值。
    9. WIFSIGNALED(status) 如果子进程被信号终止,返回真
    10. WTERMSIG(status) 检测被几号信号终止。只有上个宏为真的时候,才使用。
    11. 返回值:
    12. -1 错误
    13. 返回终止的子进程的pid


    代码示例

    • wait.c

    1. #include <stdio.h>
    2. #include <unistd.h>
    3. #include <stdlib.h>
    4. #include <sys/types.h>
    5. #include <sys/wait.h>
    6. int main(void){
    7. pid_t pid;
    8. int s;
    9. //创建子进程
    10. pid=fork();
    11. if(pid==-1){
    12. perror("fork");
    13. return 1;
    14. }
    15. if(pid==0){
    16. printf("child pid=%d\n",\
    17. getpid());
    18. //sleep(5);
    19. getchar();
    20. exit(-1);
    21. }else{
    22. //等待子进程的结束
    23. wait(&s);
    24. if(WIFEXITED(s)){
    25. //子进程正常终止
    26. printf("status:%d\n", WEXITSTATUS(s));
    27. }
    28. //检测子进程是否被信号终止
    29. if(WIFSIGNALED(s)){
    30. //输出终止子进程的信号编号
    31. printf("signum :%d\n",\
    32. WTERMSIG(s));
    33. }
    34. printf("parent...\n");
    35. }
    36. return 0;
    37. }
    • 执行结果

    a91a4f3c3e0ef16dea01e91d9fe2f955.png

    waitpid

    pid_t waitpid(pid_t pid,int *status,int options);

    1. 功能:等待进程改变状态。
    2. 参数:
    3. pid:
    4. < -1: pid取绝对值,如果子进程的组id等于这个绝对值,那么这个子进程就被等待。
    5. -1:等待任意子进程
    6. 0:等待和当前进程有同一个组id的子进程
    7. > 0 等待子进程的pid是pid参数的子进程。
    8. status:同wait(2)参数的使用
    9. options:
    10. WNOHANG:非阻塞回收。
    11. 0 阻塞回收
    12. 返回值:
    13. -1 错误
    14. 0 没有子进程退出
    15. 回收的子进程的pid

    代码示例

    • waitpid.c

    1. #include <stdio.h>
    2. #include <unistd.h>
    3. #include <stdlib.h>
    4. #include <sys/types.h>
    5. #include <sys/wait.h>
    6. int main(void){
    7. pid_t pid;
    8. int s;
    9. //创建子进程
    10. pid=fork();
    11. if(pid==-1){
    12. perror("fork");
    13. return 1;
    14. }
    15. if(pid==0){
    16. printf("child pid=%d\n",\
    17. getpid());
    18. //sleep(5);
    19. getchar();
    20. exit(-1);
    21. }else{
    22. //非阻塞等待子进程的结束
    23. waitpid(-1,&s,WNOHANG);
    24. if(WIFEXITED(s)){
    25. //子进程正常终止
    26. printf("status:%d\n", WEXITSTATUS(s));
    27. }
    28. //检测子进程是否被信号终止
    29. if(WIFSIGNALED(s)){
    30. //输出终止子进程的信号编号
    31. printf("signum :%d\n",\
    32. WTERMSIG(s));
    33. }
    34. printf("parent...\n");
    35. }
    36. return 0;
    37. }
    • 执行结果

    d8c88d11453e31fe408ee51229cfef6b.png

    给指定进程发送信号(kill)

    kill -[信号编号] [进程的pid]


    僵尸进程

    子进程已经终止,但是父进程还没有回收子进程的资源,这时候的子进程处于僵尸状态,成为僵尸进程。


    代码示例

    • zombile.c

    1. #include <stdio.h>
    2. #include <sys/types.h>
    3. #include <sys/wait.h>
    4. #include <unistd.h>
    5. #include <stdlib.h>
    6. int main(void){
    7. pid_t pid;
    8. pid=fork();
    9. if(pid==-1){
    10. perror("fork");
    11. return 1;
    12. }
    13. if(pid==0){
    14. exit(0);
    15. }else{
    16. sleep(20);
    17. wait(NULL);
    18. }
    19. return 0;
    20. }

    在进程的虚拟地址空间加载新的映像

    在子进程的虚拟地址空间加载新的影像,需要使用系统提供的一个家族的函数。

    execl(3)

    1. #include <unistd.h>
    2. extern char **environ;
    3. int execl(const char *path, const char *arg, ...);
    4. int execlp(const char *file, const char *arg, ...);
    5. int execle(const char *path, const char *arg,\
    6. ..., char * const envp[]);
    7. int execv(const char *path, char *const argv[]);
    8. int execvp(const char *file, char *const argv[]);
    9. int execvpe(const char *file, char *const argv[],
    10.                   char *const envp[]);

    execve(2)

    1. #include <unistd.h>
    2. int execve(const char *filename, char *const argv[],\
    3. char *const envp[]);
    4. 相同的exec
    5. l list
    6. v vector
    7. p PATH
    8. e 环境变量
    9. 返回值:
    10. 成功调用永远不返回
    11. -1  错误   errno被设置

    代码示例

    • exec.c

    1. #include <stdio.h>
    2. #include <unistd.h>
    3. #include <sys/types.h>
    4. #include <sys/wait.h>
    5. char *const ps_argv[]={"ps","-o","pid,ppid,pgrp,comm",NULL};
    6. int main(void){
    7. pid_t pid;
    8. //创建子进程
    9. pid=fork();
    10. if(pid ==-1){
    11. perror("fork");
    12. return 1;
    13. }
    14. if(pid==0){
    15. //加载新映像
    16. //execl("/bin/ps","ps","-o",\
    17. "pid,ppid,pgrp,comm",NULL);
    18. //execlp("ps","ps","-o",\
    19. "pid,ppid,pgrp,comm",NULL);
    20. execvp("ps",ps_argv);
    21. }else{
    22. wait(NULL);
    23. }
    24. return 0;
    25. }
    • 执行结果

    25fce74f245249fc72b63c671c1e9313.png

    使用 system 启动新的可执行程序

    1. #include <stdlib.h>
    2. int system(const char *command);
    3. 功能:执行一个shell命令
    4. 参数:
    5. command:可执行命令
    6. 返回值:
    7. -1 错误
    8. 返回command的退出状态码。

    代码示例

    • system.c

    1. #include <stdio.h>
    2. #include <sys/types.h>
    3. #include <sys/wait.h>
    4. #include <stdlib.h>
    5. #include <unistd.h>
    6. int main(void){
    7. pid_t pid;
    8. pid=fork();
    9. if(pid==-1){
    10. return 1;
    11. }
    12. if(pid==0){
    13. execl("./myt","myt",NULL);
    14. //system("myt");
    15. exit(0);
    16. }else{
    17. wait(NULL);
    18. }
    19. return 0;
    20. }
    • 执行结果

    ddf671c10a8bd22d043d24bade745daf.png

    另外,作者在蓝桥云课上线了《Linux 操作系统原理剖析》,以 Linux 操作系统为基础对操作系统实现原理进行深入讲解,分析操作系统中的内存管理、进程管理、文件系统管理、设备管理、网络管理等几大子模块的实现原理。

    3224e0f4303d34707b4897bcca5fd8a1.png

    如果想学此门课程,欢迎扫文末二维码优惠学!除此之外,大家还可选择教育优惠哦~

    129f67368d939806f8f91c10221e2a52.png

    号外!号外!

    蓝桥云课专属教育优惠重磅上线啦!

    43cf975b50a479f817f691edaa9af4ee.png

    仅需完成学生认证

    即享 5 折学生优惠券

    ▼扫码完成学生认证▼

    b590a960c3ecda4f1fdd6139dc0fe95a.png

    ▲课程优惠学▲

    ccbdf7d32ed821f7636df09cd704ca43.gif

    戳戳“阅读原文”直达课程页面!

  • 相关阅读:
    【Deep Dive:AI Webinar】我们是否能将开源许可用于机器学习和人工智能模型?
    运放的“虚短”和“虚断”
    java swing 布局心得(避免忘记)
    亿图脑图MindMaster(Pro)
    P1534 不高兴的津津(升级版)
    浙江大学机器学习(胡浩基)学习笔记二:人工神经网络、深度学习
    力扣:96.不同的二叉搜索树
    mycat的部署及测试 (读写分离)
    小米笔试题——01背包问题变种
    【微服务~Nacos】Nacos服务提供者和服务消费者
  • 原文地址:https://blog.csdn.net/MOY37RQW1JarN33BgZk/article/details/125288813