linux 基础,你掌握了几个?_linux基本了解

进程的退出

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);
}

  • 执行结果
  • 注册进程结束调用函数

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

    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);
    }
    
    
  • 执行结果
  • 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;
    }
    
    
  • 执行结果
  • 进程资源的回收

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


    使用 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;
    }
    
    


    • 执行结果

    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;
    }
    
    


    • 执行结果

    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;
    }
    
    


    • 执行结果

    给指定进程发送信号(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;
    }
    
    
  • 执行结果
  • 使用 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;
    }
  • 执行结果
  • 另外,作者在蓝桥云课上线了《Linux 操作系统原理剖析》,以 Linux 操作系统为基础对操作系统实现原理进行深入讲解,分析操作系统中的内存管理、进程管理、文件系统管理、设备管理、网络管理等几大子模块的实现原理。


    原文链接:,转发请注明来源!