Linux进程与终端学习笔记

Linux进程与终端学习笔记

进程与程序的区别

  • 程序:二进制文件,存储在磁盘上

  • 进程:process,一个程序运行实例

    • 将程序从磁盘加载到内存并分配对应的资源、调度运行
  • 进程实例

    • 汇编指令代码、数据、资源、状态
    • 一个虚拟计算机(进程上下文环境、CPU状态寄存器)
    • 进程资源:虚拟内存、打开的文件描述符表、信号、工作目录…
  • 进程由操作系统来调度管理.

  • 程序是静态的

  • 进程是动态的

创建一个进程:fork

系统调用:fork()

  • 函数原型:pid_t fork(void);
  • 函数作用:创建一个新进程
  • 返回值:
    • -1 :创建子进程失败
    • 0 :在子进程中返回0
    • >0 :在父进程中返回的是子进程的PID

子进程的运行

子进程拷贝父进程

  • 代码、数据、堆栈内存
  • 进程资源:打开的文件描述符、信号、缓冲区…
    Linux进程与终端学习笔记

执行一个二进制程序文件

Linux进程与终端学习笔记

execvp函数

**函数原型:int execvp (const char file, char const argv[]);

  • 功能说明:将当前进程的代码使用file程序文件代替并执行
  • 参数说明
    • file:要执行的程序名称
    • argv:要执行的程序文件的参数列表,参数列表以NULL指针为结束标记
  • 返回值
    • 成功:无返回值
    • 失败:返回-1,并设置errno值

exec函数簇

  • #include <unistd.h>
  • int execl (const char *path, const char *arg, …);
  • int execlp (const char *file, const char *arg, …);
  • int execle (const char *path, const char *arg, …);
  • 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[]);

exec函数簇命名规则

  • L:参数以列表的形式提供
  • V:参数以数组(向量)的方式提供
  • E:为新进程提供新的环境变量
  • P:在用户的绝对路径path下查找可执行文件,该文件必须在用户路径下,可以只指定程序文件名

写时复制(COW)与vfork

一个新进程的诞生:虚拟空间

Linux进程与终端学习笔记

一个新进程的诞生:物理空间

Linux进程与终端学习笔记

一个新进程的诞生

Linux进程与终端学习笔记

写时复制(copy-on-write)

对fork-exec流程的改进

  • 对于代码段、数据段等,父子进程可以共享,节省拷贝开销
  • 父子进程的页表项均指向同一块物理内存页帧
  • 当子进程进程空间的内容要修改时,才会真正将段复制到子进程
  • 写时复制:
    • 仅仅为子进程复制父进程的虚拟页表项
    • 对将要修改的页面修改页表项

Linux进程与终端学习笔记

系统调用:vfork

  • 对fork的改进
  • 对fork的改进更为彻底、简单粗暴
  • vfork是为子进程立即执行exec的程序而专门设计的
    • 无需为子进程复制虚拟内存页或页表,子进程直接共享父进程的资源,直到其成功执行exec或是调用exit退出
    • 在子进程调用exec之前,将暂停执行父进程

进程的退出

终止当前进程exit函数

  • POSIX标准和ANSI C定义的标准函数
    • #include <stdlib.h>
    • 其实是对系统调用_exit的封装
  • 函数原型:void exit (int status);
  • 函数功能:终止当前进程
  • 参数说明:用于标识进程的退出状态,shell或父进程可以获取该值
    • 0:表示进程正常退出
    • -1/1:表示进程退出异常
    • 2~n:用户可自定义

exit函数背后

执行流程

  • 调用退出处理程序(通过atexit、on_exit注册的函数)
  • 刷新stdio流缓冲区
  • 使用由status提供的值执行_exit系统调用函数
    • 关闭进程打开的文件描述符、释放进程持有的文件锁
    • 关闭进程打开的信号量、消息队列
    • 取消该进程通过mmap创建的内存映射

atexit/on_exit

  • 退出处理程序
  • 在exit退出后可以自动执行用户注册的退出处理程序
  • 执行顺序与注册顺序相反
  • 函数原型:int atexit (void (*function)(void));
  • 函数原型:int on_exit (void (*function)(int , void *), void *arg);

TIPS

return与exit的区别

  • exit用来终止当前进程,将控制权交给操作系统
  • return用来退出当前函数,销毁栈帧,返回到上级函数执行
  • 终止进程:
    • 正常退出:exit、_exit、从main函数return
    • 异常退出:调用abort、信号ctrl + C

exit_group函数

  • 函数原型: void exit_group (int status);
  • exit:退出当前进程process
  • exit_group:退出一个进程中所有threads
  • Linux系统特有的系统调用,不属于POSIX标准

other

  • fork之后、exec之前,使用exit是不安全的
  • 很多资源还是共享的(如文件描述符、缓冲区)

exit与_exit

两者的区别

  • exit是库函数是对_exit系统调用的封装
  • 在调用_exit之前,它会执行各种动作
    • 调用退出处理程序(通过atexit和on_exit注册的回调函数)
    • 刷新stdio流缓冲区
    • 使用由status提供的值执行_exit系统调用

_exit的执行流程

  • 关闭进程打开的文件描述符、释放该进程持有的文件锁
  • 关闭该进程打开的信号量、消息队列
  • 取消该进程通过mmap()创建的内存映射
  • 将该进程的所有子进程交给init托管
  • 给父进程发送一个SIGCHLD信号
  • ……

_exit和exit总结

  • 在一个进程中,直接调用_exit终止进程,缓冲区的数据可能会丢失
  • 在创建子进程的应用中,只应有一个进程(一般为父进程)调用exit终止,而其他进程应调用_exit()终止。从而确保只有一个进程调用退出处理程序并刷新stdio缓冲区
  • 如果一个进程使用atexit/on_exit注册了退出管理程序,则应使用exit终止程序的运行,否则注册的回调函数无法执行
上一篇:google colab 安装fuel时出现ERROR: Command errored out with exit status 1:的解决方案


下一篇:退出进程 替换接口