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

  

  

  

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

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

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

 

十八、Linux 进程与信号---进程介绍的更多相关文章

  1. 二十二、Linux 进程与信号---进程创建

    22.1 fork 和 vfork 函数 22.1.1 函数说明 #include <unistd.h> #include <sys/types.h> pid_t fork( ...

  2. 二十二、Linux 进程与信号---进程创建(续)

    22.2 父子进程操作文件 文件操作由两种模式: IO 系统调用操作文件 标准C IO 操作文件 看代码: #include <unistd.h> #include <string. ...

  3. 二十七、Linux 进程与信号---进程组和组长进程

    27.1 进程组 27.1.1 进程组介绍 进程组为一个或多个进程的集合 进程组可以接受同一终端的各种信号,同一个信号发送进程组等于发送给组中的所有进程 每个进程组有唯一的进程组 ID 进程组的消亡要 ...

  4. 二十三、Linux 进程与信号---进程链和进程扇、守护进程和孤儿进程以及僵尸进程

    23.1 进程链和进程扇 23.1.1 概念 进程链:一个父进程构建出一个子进程,子进程再构建出子子进程,子子进程构建出子子子进程.... 这种就为进程链 进程扇:一个父进程构建出多个子进程,子进程都 ...

  5. 二十一、Linux 进程与信号---进程查看和进程状态、进程调度和进程状态变化、进程标识

    21.1 进程查看和进程状态 21.1.1 ps 指令 ps 指令通常可以查看到进程的 ID.进程的用户 ID.进程状态和进程的 Command ps:查看当前用户启动的进程 ps -ef:详细查看后 ...

  6. 二十一、Linux 进程与信号---进程资源限制

    21.1 进程资源限制 在操作系统中,我们能够通过函数getrlimit().setrlimit()分别获得.设置每个进程能够创建的各种系统资源的限制使用量. 21.1.1 函数 #include & ...

  7. python成长之路【第十八篇】:python模块介绍、模块导入和重载

    一.模块和命名空间 一般来说,Python程序往往由多个模块文件构成,通过import语句连接在一起.每个模块文件是一个独立完备的变量包,即一个命名空间.一个模块文件不能看到其他文件定义的变量名,除非 ...

  8. robotframework的学习笔记(十八)——RequestsLibrary库的API介绍

    requestsLibrary的关键字不多,常用的就几个. Create Session: 创建一个session,连接某个服务器.Create Ntlm Session: 也是创建一个session ...

  9. 二十八、Linux 进程与信号---前台进程组

    28.1 介绍 28.1.1 概念 自动接受终端信号的组称为前台进程组 在终端通过 ctrl + c 等动作产生的信号首先被前台进程组接受 在 shell 启动的若干个进程组默认是父进程所在的组为前台 ...

随机推荐

  1. luogu1983 车站分级 (拓扑排序)

    对每趟车建一个虚点p,对于不停车的x,连边(x,p,1):对于停车的y,连边(p,y,0)有一条边(a,b,l)就是说b-a>=l由于题目保证一定能走,直接拓扑序dp算最大的就行了 #inclu ...

  2. layui记录

    layui 官网 layui 独立版 layui mobile layui 社区

  3. 工作笔记:/bin/bash^M: 坏的解释器: 没有那个文件或目录 问题解决

    问题原因: 由于windows上换行符为CR LF而在Linux下是 LF 导致出现上述问题 解决方案 1. 在windows下 可以使用nodepad打开该shell文件,然后将shell文件中的格 ...

  4. Codeforces Round #512 D - Vasya and Triangle

    D - Vasya and Triangle #include<bits/stdc++.h> using namespace std; #define LL long long LL gc ...

  5. SpringBoot整合阿里Druid数据源及Spring-Data-Jpa

    SpringBoot整合阿里Druid数据源及Spring-Data-Jpa https://mp.weixin.qq.com/s?__biz=MzU0MDEwMjgwNA==&mid=224 ...

  6. jenkins学习:jenkins+gitlab

    配置前提: 1.Jenkins已安装git plugin,gitlab plugin,安装过程可参考 https://www.cnblogs.com/zhizhiyin/p/9138309.html ...

  7. PHP工厂方法模式

    此模式中,通过定义一个抽象的核心工厂类,并定义创建产品对象的接口,创建具体产品实例的工作延迟到其工厂子类去完成.这样做的好处是核心类只关注工厂类的接口定义,而具体的产品实例交给具体的工厂子类去创建.当 ...

  8. JS学习笔记Day5

    一.变量的作用域 1.作用域:变量的作用范围 2.全局变量:变量在整个程序都是有效的(从程序开始到程序结束变量均有效)在函数体外部定义的变量都是全局变量:在函数体内部 没有用var定义的变量也有可能是 ...

  9. node.js小案例_留言板

    一.前言 通过这个案例复习: 1.node.js中模板引擎的使用 2.node.js中的页面跳转和重定向 二.主要内容 1.案列演示:  2.案列源码:https://github.com/45612 ...

  10. python对象的不同参数集合

    如下,我们已经有了一个从Contact类继承过来的Friend类 class ContactList(list): def search(self, name): '''Return all cont ...