linux基础——进程的退出及资源回收

简介: linux基础——进程的退出及资源回收

文章目录

进程的退出

returen 和 exit

代码示例

注册进程结束调用函数

代码示例(on_exit):

atexit

代码示例(atexit)

进程资源的回收

代码示例

wait回收进程资源

代码示例

waitpid

代码示例

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

僵尸进程

代码示例

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

代码示例

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

代码示例


进程的退出

returen 和 exit

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


void exit(int status);


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


代码示例

  • test.c
#include <stdio.h>
#include <stdlib.h>
int main(void){
  getchar();
  exit(-1);
}


  • 执行结果

20200205205519469.png

注册进程结束调用函数

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

on_exit(3)


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


代码示例(on_exit):

  • on_exit.c
#include <stdio.h>
#include <stdlib.h>
void doit(int n,void *arg){
  printf("n=%d\targ:%s\n",\
  n,(char *)arg);
  return;
}
int main(void){
  //向进程注册退出函数
  on_exit(doit,"beijing");
  getchar();
  exit(3);
}


  • 执行结果

20200205212023579.png

atexit

atexit(3)


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


代码示例(atexit)

  • atexit.c
#include <stdio.h>
#include <stdlib.h>
//注册给进程的退出函数
void doit(void){
  printf("hahha....\n");
  return;
}
int main(void){
  //向进程注册一个退出处理函数
  atexit(doit);
  getchar();
  return 0;
}


  • 执行结果

20200205212417685.png

进程资源的回收

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

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

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


代码示例

  • lonely.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(void){
  pid_t pid;
  //创建子进程
  pid=fork();
  if(pid==-1){
  perror("fork");
  return 1;
  }
  if(pid==0){//子进程的代码
  sleep(5);
  printf("child...\n");
  //getchar();
  exit(0);
  }else{//父进程的代码
  printf("parent...\n");
  exit(0);
  }
  return 0;
}


  • 执行结果

20200205213053718.png

wait回收进程资源

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


代码示例

  • wait.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void){
  pid_t pid;
  int s;
  //创建子进程
  pid=fork();
  if(pid==-1){
  perror("fork");
  return 1;
  }
  if(pid==0){
  printf("child pid=%d\n",\
    getpid());
  //sleep(5);
  getchar();
  exit(-1);
  }else{
  //等待子进程的结束
  wait(&s);
  if(WIFEXITED(s)){
    //子进程正常终止
    printf("status:%d\n",     WEXITSTATUS(s));
  }
  //检测子进程是否被信号终止
  if(WIFSIGNALED(s)){
    //输出终止子进程的信号编号
    printf("signum :%d\n",\
    WTERMSIG(s));
  }
  printf("parent...\n");
  }
  return 0;
}


  • 执行结果

20200205214023156.png

waitpid

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


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


代码示例

  • waitpid.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void){
  pid_t pid;
  int s;
  //创建子进程
  pid=fork();
  if(pid==-1){
  perror("fork");
  return 1;
  }
  if(pid==0){
  printf("child pid=%d\n",\
    getpid());
  //sleep(5);
  getchar();
  exit(-1);
  }else{
  //非阻塞等待子进程的结束
  waitpid(-1,&s,WNOHANG);
  if(WIFEXITED(s)){
    //子进程正常终止
    printf("status:%d\n",     WEXITSTATUS(s));
  }
  //检测子进程是否被信号终止
  if(WIFSIGNALED(s)){
    //输出终止子进程的信号编号
    printf("signum :%d\n",\
    WTERMSIG(s));
  }
  printf("parent...\n");
  }
  return 0;
}


  • 执行结果

20200205214449872.png

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

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


僵尸进程

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


代码示例

  • zombile.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int main(void){
  pid_t pid;
  pid=fork();
  if(pid==-1){
  perror("fork");
  return 1;
  }
  if(pid==0){
  exit(0);
  }else{
  sleep(20);
  wait(NULL);
  }
  return 0;
}


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

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


execl(3)


#include <unistd.h>
extern char **environ;
int execl(const char *path,  const  char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const  char *arg,\
              ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const   char  *file,  char *const argv[],
                  char *const envp[]);


execve(2)


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


代码示例

  • exec.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
char *const ps_argv[]={"ps","-o","pid,ppid,pgrp,comm",NULL};
int main(void){
  pid_t pid;
  //创建子进程
  pid=fork();
  if(pid ==-1){
  perror("fork");
  return 1;
  }
  if(pid==0){
  //加载新映像
  //execl("/bin/ps","ps","-o",\
  "pid,ppid,pgrp,comm",NULL);
  //execlp("ps","ps","-o",\
  "pid,ppid,pgrp,comm",NULL);
  execvp("ps",ps_argv);
  }else{
  wait(NULL);
  }
  return 0;
}


  • 执行结果:

20200205215929431.png

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

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


代码示例

  • system.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
int main(void){
  pid_t pid;
  pid=fork();
  if(pid==-1){
  return 1;
  }
  if(pid==0){
  execl("./myt","myt",NULL);
  //system("myt");
  exit(0);
  }else{
  wait(NULL);
  }
  return 0;
}


  • 执行结果

2020020522040989.png

相关文章
|
6天前
|
缓存 监控 Linux
linux进程管理万字详解!!!
本文档介绍了Linux系统中进程管理、系统负载监控、内存监控和磁盘监控的基本概念和常用命令。主要内容包括: 1. **进程管理**: - **进程介绍**:程序与进程的关系、进程的生命周期、查看进程号和父进程号的方法。 - **进程监控命令**:`ps`、`pstree`、`pidof`、`top`、`htop`、`lsof`等命令的使用方法和案例。 - **进程管理命令**:控制信号、`kill`、`pkill`、`killall`、前台和后台运行、`screen`、`nohup`等命令的使用方法和案例。
30 4
linux进程管理万字详解!!!
|
6天前
|
算法 Linux 定位技术
Linux内核中的进程调度算法解析####
【10月更文挑战第29天】 本文深入剖析了Linux操作系统的心脏——内核中至关重要的组成部分之一,即进程调度机制。不同于传统的摘要概述,我们将通过一段引人入胜的故事线来揭开进程调度算法的神秘面纱,展现其背后的精妙设计与复杂逻辑,让读者仿佛跟随一位虚拟的“进程侦探”,一步步探索Linux如何高效、公平地管理众多进程,确保系统资源的最优分配与利用。 ####
30 4
|
7天前
|
缓存 负载均衡 算法
Linux内核中的进程调度算法解析####
本文深入探讨了Linux操作系统核心组件之一——进程调度器,着重分析了其采用的CFS(完全公平调度器)算法。不同于传统摘要对研究背景、方法、结果和结论的概述,本文摘要将直接揭示CFS算法的核心优势及其在现代多核处理器环境下如何实现高效、公平的资源分配,同时简要提及该算法如何优化系统响应时间和吞吐量,为读者快速构建对Linux进程调度机制的认知框架。 ####
|
8天前
|
消息中间件 存储 Linux
|
14天前
|
运维 Linux
Linux查找占用的端口,并杀死进程的简单方法
通过上述步骤和命令,您能够迅速识别并根据实际情况管理Linux系统中占用特定端口的进程。为了获得更全面的服务器管理技巧和解决方案,提供了丰富的资源和专业服务,是您提升运维技能的理想选择。
16 1
|
26天前
|
算法 Linux 调度
深入理解Linux操作系统的进程管理
【10月更文挑战第9天】本文将深入浅出地介绍Linux系统中的进程管理机制,包括进程的概念、状态、调度以及如何在Linux环境下进行进程控制。我们将通过直观的语言和生动的比喻,让读者轻松掌握这一核心概念。文章不仅适合初学者构建基础,也能帮助有经验的用户加深对进程管理的理解。
18 1
|
1月前
|
消息中间件 Linux API
Linux c/c++之IPC进程间通信
这篇文章详细介绍了Linux下C/C++进程间通信(IPC)的三种主要技术:共享内存、消息队列和信号量,包括它们的编程模型、API函数原型、优势与缺点,并通过示例代码展示了它们的创建、使用和管理方法。
26 0
Linux c/c++之IPC进程间通信
|
1月前
|
Linux C++
Linux c/c++进程间通信(1)
这篇文章介绍了Linux下C/C++进程间通信的几种方式,包括普通文件、文件映射虚拟内存、管道通信(FIFO),并提供了示例代码和标准输入输出设备的应用。
22 0
Linux c/c++进程间通信(1)
|
1月前
|
Linux C++
Linux c/c++之进程的创建
这篇文章介绍了在Linux环境下使用C/C++创建进程的三种方式:system函数、fork函数以及exec族函数,并展示了它们的代码示例和运行结果。
30 0
Linux c/c++之进程的创建
|
1月前
|
Linux C++
Linux c/c++进程之僵尸进程和守护进程
这篇文章介绍了Linux系统中僵尸进程和守护进程的概念、产生原因、解决方法以及如何创建守护进程。
17 0
下一篇
无影云桌面