linux 基础,你掌握了几个?

86479b736688f41dcf6e0136c92a6b96.png

点击蓝字 关注我们

c29364f22a5fc75635edd2a34e33a498.png

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

41bd004542c3493204900669217dbca0.png

进程的退出

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);
}
  • 执行结果

8fce68633c6566e7f6b48d65ae44dd9d.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);
}
  • 执行结果

c08a2bc1d1e0278c786d049fe3ed2f59.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;
}
  • 执行结果

91b55aec148f0f30c38229c855cc4d21.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;
}
  • 执行结果

3174aef4f30417d4e223d23ee578db92.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;
}
  • 执行结果

a91a4f3c3e0ef16dea01e91d9fe2f955.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;
}
  • 执行结果

d8c88d11453e31fe408ee51229cfef6b.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;
}
  • 执行结果

25fce74f245249fc72b63c671c1e9313.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;
}
  • 执行结果

ddf671c10a8bd22d043d24bade745daf.png

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

3224e0f4303d34707b4897bcca5fd8a1.png

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

129f67368d939806f8f91c10221e2a52.png

号外!号外!

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

43cf975b50a479f817f691edaa9af4ee.png

仅需完成学生认证

即享 5 折学生优惠券

▼扫码完成学生认证▼

b590a960c3ecda4f1fdd6139dc0fe95a.png

▲课程优惠学▲

ccbdf7d32ed821f7636df09cd704ca43.gif

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值