• 十八、Linux 进程与信号---进程介绍


    18.1 进程的概念

    • 程序:程序(program)是存放再磁盘文件中的可执行文件
    • 进程
      • 程序的执行实例被称为进程(process)
      • 一个程序的执行实例可能由多个
      • 进程具有独立的权限和职责。如果系统中某个进程崩溃,它不会影响到其余的进程。
      • 每个进程运行在其各自的虚拟地址空间中,进程之间可以通过由内核控制的机制相互通讯
    • 进程ID
      • 每个 Linux 进程都一定由一个唯一的数字标识符,称为进程ID(process ID),进程ID总是一非负整数   

    18.2 内核中的进程结构体

      每一个启动进程都有一个 task_struct 结构,这是个结构体,命名为进程表项(或 进程控制块)如下:

      

      启动一个程序操作文件的过程如下:进程启动创建一个 task_struct 进程表项,进程表项中有一个成员指向文件描述符表

      

    18.3 进程的启动和终止

      进程的启动和退出如下:

      main 运行的时候,内核会帮忙启动一个例程(C start template),启动例程会帮忙启动 main 函数,并帮忙收集命令行参数,环境参数等等,调用结束以后,main 返回给启动例程。

      若是调用 exit() 函数,就不会返回给main 函数或其他函数了。exit() 直接调用内核所提供的系统调用退出函数。

      atexit 函数为注册退出函数。

      

    18.3.1 内核启动特殊例程

    • 启动例程
      • 在进程的 main 函数执行之前内核会启动
      • 该例程放置在 /lib/libc.so.*** 中
      • 编译器在编译时会将启动例程编译进可执行文件中
    • 启动例程的作用

      • 搜集命令行的参数传递给 main 函数中的 argc 和 argv
      • 搜集环境信息构建环境表并传递给 main 函数
      • 登记进程的终止函数  

    18.3.2 进程的终止方式

    • 正常终止

      • 从main 函数返回 return
      • 调用 exit (标准C 库函数)
      • 调用 _exit 或 _Exit(系统调用)
      • 最后一个线程从其启动例程返回
      • 最后一个线程调用 pthread_exit  
    • 异常终止

      • 调用 abort
      • 接受一个信号并终止
      • 最后一个线程对取消请求做处理响应  
    • 进程返回   

      • 通常程序运行成功返回0,否则返回 非 0
      • 在 shell 中可以查看进程返回值( echo $?) 

      进程终止方式区别

      

    18.3.2.1 内核登记进程终止函数---atexit 函数

    1 #include <stdlib.h>
    2 int atexit (void (*function)(void));
    • 相关函数 _exit,exit,on_exit
    • 函数说明:
      • atexit()用来设置一个程序正常结束前调用的函数。
      • 当程序通过调用exit()或从main中返回时,参数function所指定的函数会先被调用,然后才真正由exit()结束程序。
    • 函数功能
      • 向内核登记终止函数  
    • 返回值:
      • 如果执行成功则返回0,否则返回-1,失败原因存于errno中。
    • 其他说明
      • 每个启动的进程都默认登记了一个标准的终止函数
      • 终止函数在进程终止时释放进程所占用的一些资源
      • 登记的多个终止函数执行顺序是以 栈的方式执行,先登记的后执行  

    18.3.2.2 例子

     

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 #include <string.h>
     4 #include <stdlib.h>
     5 #include <fcntl.h>
     6 
     7 //定义进程的终止函数
     8 void term_fun1(void)
     9 {
    10     printf("first term function
    ");
    11 }
    12 
    13 void term_fun2(void)
    14 {
    15     printf("second term function
    ");
    16 }
    17 
    18 void term_fun3(void)
    19 {
    20     printf("third term function
    ");
    21 }
    22 
    23 int main(int argc, char *argv[])
    24 {
    25     if(argc < 3) {
    26         fprintf(stderr, "usage: %s file [exit | _exit | return]
    ", argv[0]);
    27         exit(1);
    28     }
    29 
    30     //向进程登记终止函数
    31     atexit(term_fun1);
    32     atexit(term_fun2);
    33     atexit(term_fun3);
    34 
    35     FILE *fp = fopen(argv[1], "w+");
    36     fprintf(fp, "hello world");
    37 
    38     if(!strcmp(argv[2], "exit")) {
    39         exit(0);//标准C 的库函数
    40     } else if(!strcmp(argv[2], "_exit")) {
    41         _exit(0);//系统调用
    42     } else if(!strcmp(argv[2], "return")) {
    43         return 0;
    44     } else {
    45         fprintf(stderr, "usage: %s file [exit | _exit | return]
    ", argv[0]);
    46     }
    47 
    48     exit(0);
    49 }

      

      

      

      结果是前两种可以正常运行,并且对文件可以正常写入,但是第三种方式无输出,且文件创建了,但没有写入。

      而且可以看见终止方式是以栈的方式进行调用的。

      可以知道选用 _EXIT和_exit 系统调用的时候,不会进行调用。之所以没有输出,代码中向文件写入数据的时候,表现为全缓存,这些数据可能还存放在缓存中,并没有从缓存中释放出来。带代码中加入 fclose 函数或程序终止后,会自动清缓存,但是系统调用 _exit 和 _EXIT 不会自动刷新缓存。

     

  • 相关阅读:
    进程(WINAPI),遍历并查找树状的进程信息,实现控制系统进程
    HDU 4786 Fibonacci Tree(生成树,YY乱搞)
    Linux信号通讯编程
    HDU 3635 Dragon Balls(带权并查集)
    还原数据库出现“未获得排他訪问”解决方法(杀死数据库连接的存储过程sqlserver)
    java.sql.SQLException: [Microsoft][ODBC 驱动程序管理器] 未发现数据源名称而且未指定默认驱动程序解决方法
    【C++基础 02】深拷贝和浅拷贝
    内核链接的简单使用
    I2C测试【转】
    [RK3288]PMU配置(RK808)【转】
  • 原文地址:https://www.cnblogs.com/kele-dad/p/9108243.html
Copyright © 2020-2023  润新知