《Linux操作系统编程》 第六章 Linux中的进程监控: fork函数的使用,以及父子进程间的关系,掌握exec系列函数

这篇具有很好参考价值的文章主要介绍了《Linux操作系统编程》 第六章 Linux中的进程监控: fork函数的使用,以及父子进程间的关系,掌握exec系列函数。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

《Linux操作系统编程》 第六章 Linux中的进程监控: fork函数的使用,以及父子进程间的关系,掌握exec系列函数,Linux,linux,java,面试

《Linux操作系统编程》 第六章 Linux中的进程监控: fork函数的使用,以及父子进程间的关系,掌握exec系列函数,Linux,linux,java,面试

🌷🍁 博主 libin9iOak带您 Go to New World.✨🍁
🦄 个人主页——libin9iOak的博客🎐
🐳 《面试题大全》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺
🌊 《IDEA开发秘籍》学会IDEA常用操作,工作效率翻倍~💐
🪁🍁 希望本文能够给您带来一定的帮助🌸文章粗浅,敬请批评指正!🍁🐥

《Linux操作系统编程》 第六章 Linux中的进程监控: fork函数的使用,以及父子进程间的关系,掌握exec系列函数,Linux,linux,java,面试

第六章 Linux中的进程监控

学习目的

使学生理解Linux中进程控制块的数据结构,Linux进程的创建、执行、终止、等待以及监控方法。并重点掌握fork函数的使用以及exec系列函数。

学习要求

了解:Linux进程控制块的数据结构以及进程的状态,进程的内存空间布局,特殊进程。

理解:Linux进程创建时环境变量、命令行参数的设置,理解父进程等待子进程结束和获得子进程返回值的原理;

掌握:fork函数的使用,以及父子进程间的关系,掌握exec系列函数。

学习方法

通过对进程运行与监控的相关知识点的编程学习和锻炼,培养学生们对进程相关实例问题进行分析与解决的能力

概念和原理

6.1 Linux的进程控制块

进程在内核中的表现形式:进程控制块(PCB)

Linux系统中的每个进程都有一个名为task_struct的数据结构,它相当于“进程控制块”。 task_struct是Linux内核的一种数据结构,它会被装载到内存中并且包含着进程的信息。

指向task_struct数据结构的指针形成了一个task数组。当建立新进程的时候,Linux为新进程分配一个task_struct结构,然后将指针保存在task数组中。调度程序一直维护着一个current指针,它指向当前正在运行的进程。

6.1.1 task_struct结构包含的信息

▪ 标识符 :描述本进程的唯一标识符,用来区别其他进程。

▪ 优先级 :相对于其他进程的优先级。

▪ 程序计数器:程序中即将被执行的下一条指令的地址。

▪ 内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。

▪ 上下文数据:进程执行时处理器的寄存器中的数据。

▪ I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。

▪ 记账信息:可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等

6.1.2 task_struct:进程标识符

​ pid_t pid; //进程的唯一标识

pid_t tgid; // 线程组中领头线程的pid值

每个进程都必须拥有它自己的进程描述符pid。

pid是32位无符号整型数据,最大值取32767。

进程标识符是内核提供给用户程序的接口,用户程序通过pid操作程序。

6.1.3 task_struct:进程状态

​ volatile long state

​ 进程状态切换

《Linux操作系统编程》 第六章 Linux中的进程监控: fork函数的使用,以及父子进程间的关系,掌握exec系列函数,Linux,linux,java,面试

图6-1 进程状态切换

6.2 Linux中进程的创建

6.2.1 Linux中进程的创建

(1) 创建进程

▪ Linux中创建进程的方式:

- 在shell中执行命令或可执行文件

- 在代码中(已经存在的进程中)调用函数创建子进程

(2) 创建子进程-fork函数

▪ 函数原型:pid_t fork(void);

▪ 返回值:

- fork函数被正确调用后,可能会在子进程中或父进程中分别返回

- 在子进程中返回值为0(不合法的PID,提示当前运行在子进程中)

- 在父进程中返回值为子进程ID(让父进程掌握所创建子进程的ID号)

- 出错返回-1

(3) fork函数工作流程

▪ 子进程是父进程的副本

- 子进程复制/拷贝父进程的PCB、用户空间(数据段、堆和栈)

- 父子进程共享正文段(只读)

▪ 父进程继续执行fork函数调用之后的代码,子进程也从fork函数调用之后的代码开始执行

▪ 为了提高效率,fork后,子进程并不立即复制父进程数据段、堆和栈,采用了写时复制机制(Copy-On-Write)

(4) fork函数执行后父子进程的主要异同

▪ 相同

- 真实用户ID,真实组ID

- 有效用户ID,有效组ID

- 环境变量

- 堆

- 栈

- 打开的文件

▪ 不同

- fork的返回值

- 子进程ID及父进程ID

- 子进程的

- tms_utime,

- tms_stime,

- tms_cutime,

- tms_ustime

(5) fork函数的用法1

▪ 父进程希望子进程复制自己(共享代码,复制数据空间),但父子进程执行相同代码中的不同分支。

▪ 例如:网络并发服务器中,父进程等待客户端的服务请求。当请求达到,父进程调用fork创建子进程处理该请求,而父进程继续等待下一个服务请求

(6) fork函数的用法2

▪ 父子进程执行不同的可执行文件(父子进程具有完全不同的代码段和数据空间)

(7) 创建子进程-vfork函数

▪ vfork用于创建新进程,而该新进程的目的是执行另外一个可执行文件

- 子进程在调用exec或exit之前,在父进程的地址空间中运行

- vfork函数保证子进程先执行,在它调用exec或者exit之后,父进程才会继续被调度执行(父进程处于TASK_UNINTERRUPTIBLE状态)

(8) 创建进程-clone函数

▪ clone():有选择的复制父进程的资源。(带参数)

▪ int clone(int (*fn)(void *), void *child_stack, int flags, void *arg);

- fn为函数指针,此指针指向一个函数体;

- child_stack为给子进程分配系统堆栈的指针(在linux下系统堆栈空间是2页面,就是8K的内存,其中在这块内存中,低地址上放入了值,这个值就是进程控制块task_struct的值);

- arg 就是传给子进程的参数,一般为(0);

- flags 为要复制资源的标志,描述需要从父进程继承那些资源。

(9) 创建进程流程

《Linux操作系统编程》 第六章 Linux中的进程监控: fork函数的使用,以及父子进程间的关系,掌握exec系列函数,Linux,linux,java,面试

图6-2 创建进程流程

(10) Linux进程空间的获取

▪ 申请空白PCB详细阐述:

- do_fork() à alloc_task_struct(void)

(11) 区别fork(),vfork(),clone()

▪ 拷贝内容

- fork():子进程拷贝父进程的数据段,代码段 。

- vfork():子进程与父进程共享数据段 ;

- clone(): 有选择的复制父进程的资源。(带参数)

- 通过参数clone_flags的设置来决定哪些资源共享,哪些资源拷贝

- CLONE_VM( 共 享 地 址 空间)

- CLONE_FS|CLONE_FILES(共享文件描述符集)

- CLONE_SIGCHLD(共享信号)

▪ 访问次序控制

- fork():父子进程的执行次序不确定 。

- vfork():保证子进程先运行,在调用execve()或exit()之前,与父进程数据是共享的。

- clone():由标志CLONE_VFORK 来决定子进程在执行时父进程是阻塞还是运行,若没有设置该标志,则父子进程同时运行; 若设置了该标志,则父进程挂起,直到子进程结束为止。

6.3 Linux中进程的执行

6.3.1 Linux中进程的执行

(1) exec系列函数

fork、vfork和clone三个函数主要是Linux用来创建新的进程(线程)而设计的,exec系列函数则是用来用指定的程序替换当前进程的所有内容。exec系列函数经常在前三个函数使用之后调用,来创建一个全新的程序运行环境。exec函数簇提供了一个在进程中启动另一个程序执行的方法。

进程调用exec系列函数在进程中加载执行另外一个可执行文件

▪ execl execv execle execve execlp execvp

▪ 六个函数开头均为exec,所以称为exec系列函数

- l:表示list,每个命令行参数都说明为一个单独的参数

- v:表示vector,命令行参数放在数组中

- e:表示由函数调用者提供环境变量表

- p:表示通过环境变量PATH来指定路径,查找可执行文件

▪ PATH环境变量说明

- PATH 环境变量包含了一张目录表,系统通过 PATH 环境变量定义的路径搜索执行码

- PATH 环境变量定义时目录之间要用“:”分隔,以“.”号表示结束。

- PATH 环境变量定义在用户的.profile或.bash_profile 中

(2) execl函数

▪ 函数原型

- 头文件:unistd.h

- int execl(const char *pathname, const char *arg0, …,NULL);

▪ 参数

- pathname:要执行程序的绝对路径名

- 可变参数:要执行程序的命令行参数,以空指针结束

▪ 返回值

- 出错返回-1

- 成功该函数不返回!

(3) execv函数

▪ 函数原型

- 头文件:unistd.h

- int execv(const char *pathname, char *const argv[]);

▪ 参数

- pathname:要执行程序的绝对路径名

- argv:数组指针维护的程序命令行参数列表,该数组的最后一个成员必须为空指针

▪ 返回值

- 出错返回-1

- 成功该函数不返回

(4) execle函数

▪ 函数原型

- 头文件:unistd.h

- int execle(const char *pathname, const char *arg0,… NULL, char *const envp[]);

▪ 参数

- pathname:要执行程序的绝对路径名

- 可变参数:要执行程序的命令行参数,以空指针结束

- envp::指向环境字符串数组的指针,该数组的最后一个成员必须为空指针

▪ 返回值

- 出错返回-1

- 成功该函数不返回

(5) 其他exec函数

▪ execve函数

- int execve(const char *pathname,char *const argv[], char *const envp[]);

▪ execlp函数

- int execlp(const char *filename,const char *arg0, …,NULL);

- filename参数可以是相对路径(路径信息从环境变量PATH中获取)

- 例如默认环境变量中包含的PATH=/bin:/usr/bin:/usr/local/bin/

▪ execvp函数

- int execvp(const char *filename,char *const argv[]);

6.4 Linux中进程的终止

6.4.1 Linux中进程的终止

(1) 进程的启动与退出

▪ 进程启动

子进程和父进程共享代码段,从fork函数执行之后的代码处开始执行;exec类函数会让进程从可执行文件的main函数开始重新执行

▪ 进程退出

当一个进程结束了运行或在半途终止了运行,那么内核就需要回收该进程除进程控制块之外所占用的系统资源(包括进程运行时打开的文件,申请的内存等),并让其他进程从进程控制块中收集有关信息

(2) Linux中进程的退出方式

▪ 正常退出

- 在main函数中执行return返回

- 在任意代码中调用exit函数或_exit函数

▪ 异常退出

- 在任意代码中调用abort函数

- 进程接收到终止信号

(3) exit和return的区别

▪ exit和_exit是函数,有参数。 exit 和_exit执行完后把控制权交给内核。

▪ return是函数执行完后的返回。renturn执行完后把控制权交给调用函数。

(4) 进程正常退出函数

▪ 头文件stdlib.h ,函数定义:void exit( int status )

▪ 头文件unistd.h,函数定义:void _exit (int status )

▪ 调用这两个函数均会正常地终止一个进程

▪ 调用_exit 函数将会立即返回内核

▪ 调用exit 函数:

- 执行一些预先注册的终止处理函数

- 执行文件I/O操作的善后工作,使得所有缓冲的输出数据被更新到相应的设备

- 返回内核

(5) 缓冲I/O方式

Linux的标准函数库中,有一种被称作 “缓冲I/O”的操作,其特征就是对应每一个打开的文件,在内存中都有一片缓冲区。每次读文件时,会连续地读出若干条记录,这样在下次读文件时就可以直接从内存的缓冲区读取;同样,每次写文件的时候也仅仅是写入内存的缓冲区,等满足了一定的条件(如达到了一定数量或遇到特定字符等),再将缓冲区中的内容一次性写入文件。

6.5 Linux中进程的等待

6.5.1 Linux中进程的等待

(1) wait函数

▪ 功能:获取任意子进程的状态改变信息(如果是终止状态则对子进程进行善后处理)

▪ 函数原型

- 头文件:sys/wait.h

- pid_t wait(int *statloc);

▪ 参数与返回值

- statloc:用于存储子进程的状态改变信息

- 返回值:若成功返回状态信息改变的子进程ID,出错返回-1

(2) waitpid函数

▪ 功能:等待某个特定子进程状态改变

▪ 函数原型

- 头文件:sys/wait.h

- pid_t waitpid(pid_t pid, int *statloc, int options);

▪ 返回值

- 成功返回终止子进程ID,失败返回-1

▪ 参数

- pid

- pid == -1: 等待任意子进程状态改变(同wait)

- pid > 0: 等待进程ID为pid的子进程状态改变

- pid == 0: 等待其组ID等于调用进程组ID的任意子进程

- pid < -1: 等待其组ID等于pid绝对值的任意子进程

- statloc:用于存储子进程的状态改变信息

- options:可以为0,也可以是以下常量

- WNOHANG:如果没有任何已经终止的子进程则马上返回, 函数不等待,此时返回值为0

- WUNTRACED:用于跟踪调试

▪ waitpid特有的功能

- waitpid可等待一个特定的进程的状态改变信息

- waitpid可以实现非阻塞的等待操作,有时希望取得子进程的状态改变信息,但不希望阻塞父进程等待子进程状态改变

- waitpid支持作业控制(进程组控制)

(3) 获知子进程状态改变

▪ 主动获取

- 调用wait或waitpid函数等待子进程状态信息改变,并获取其状态信息

▪ 异步通知

- 当一个进程发生特定的状态变化(进程终止、暂停以及恢复)时,内核向其父进程发送SIGCHLD信号

- 父进程可以选择忽略该信号,也可以对信号进行处理(默认处理方式为忽略该信号)

(4) 僵尸进程

对于已经终止但父进程尚未对其调用wait或waitpid函数的子进程称为僵尸进程(TASK_ZOMBIE状态)。

(5) 孤儿进程

如果父进程在子进程终止之前终止,则子进程的父进程将变为init进程,保证每个进程都有父进程,由init进程调用wait函数进行善后

6.6 Linux中进程的监控

(1) 进程及进程状态

▪ UNIX/Linux系统中的“进程”是可运行程序在内存中的一次运行实例。

▪ 进程和程序的主要区别是:

- 进程是动态的, 它有自己的生命周期和不同状态; 而程序是静态的, 通常存放在某种介质(如磁盘或纸张等)上。

- 进程具有运行控制结构和作用数据区;程序没有。

- 一个程序可以同时在内存中有多个运行实例, 即同时作为多个进程的组成部分。

▪ 生命周期大致分为三种状态:

- 运行态:进程正占用CPU和其它资源进行运算.

- 就绪态:进程已做好一切准备, 等待获得CPU投入运行.

- 睡眠态:进程因等待输入输出或其它系统资源, 而让出CPU资源, 等待运行条件满足。

(2) 获取进程状态信息: ps 命令

▪ 不带参数的ps命令运行时, 显示该用户当前活动进程的基本信息:

- PID 进程标识号. 系统每个进程在其生命周期都有一个唯一的

- TTY 启动该进程的终端号

- TIME 进程累计占用CPU的时间

- COMMAND 产生该进程的命令

▪ ps命令的常用任选项 -e (或-a) 显示系统中所有活动进程的信息,而不只是本用户的进程。

▪ -f 任选项:显示每个进程的完整信息,包括完整的命令行

(3) 暂停进程运行: sleep 命令

sleep time

sleep命令使运行它的进程暂停time指定的秒数.

(4) 终止进程运行: kill 命令

用户发出 kill 命令, 强行终止后台进程或键盘锁住了的前台进程的运行.

kill 命令的三种常用格式为:

  1. kill PID

正常结束进程, 自动完成所有善后工作, 作用类似于按 Del 键.

  1. kill -1 PID

先挂起该进程, 终止子进程, 完成善后工作, 再终止该进程.

  1. kill -9 PID

立即强行终止该进程, 不作任何善后工作. 可能出现资源浪费和"孤儿"进程.

重点

进程创建、执行程序和等待进程退出。

难点

​ 进程创建过程。

这部分过于抽象难以理解,通过代码导读能够更加形象一些,但是学生可能并不熟悉Linux源代码,因此需要在Linux入门章节增加代码结构介绍和阅读指导,然后布置和鼓励学生们自行阅读源代码,从而在讲解时更加方便,也更能激发学生的学习意愿。

习题

  1. 在Linux中创建进程主要有哪几种方式?

答:(1)在shell中执行命令或可执行文件。(2)在代码中(已经存在的进程中)调用函数创建子进程。

  1. 用fork()创建新进程时,子进程从父进程继承了哪些资源?

答:子进程复制/拷贝父进程的PCB、用户空间(数据段、堆和栈),父子进程共享正文段(只读)。

  1. waitpid函数的pid参数怎样设置表示等待任一子进程终止?

答:pid设置为 -1代表等待任意子进程状态改变(同wait)。

4.在Linux中什么情况下使用exec函数簇?

答:exec函数簇是用来用指定的程序替换当前进程的所有内容。exec系列函数经常在fork、vfork和clone三个函数使用之后调用,来创建一个全新的程序运行环境。exec函数簇提供了一个在进程中启动另一个程序执行的方法。

原创声明

=======

作者: [ libin9iOak ]


本文为原创文章,版权归作者所有。未经许可,禁止转载、复制或引用。

作者保证信息真实可靠,但不对准确性和完整性承担责任。

未经许可,禁止商业用途。

如有疑问或建议,请联系作者。

感谢您的支持与尊重。

点击下方名片,加入IT技术核心学习团队。一起探索科技的未来,共同成长。文章来源地址https://www.toymoban.com/news/detail-516326.html

到了这里,关于《Linux操作系统编程》 第六章 Linux中的进程监控: fork函数的使用,以及父子进程间的关系,掌握exec系列函数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux操作系统--shell编程(流程控制)

    1.if 条件判断 ①.单分支判断 if [ 条件判断式 ];then 程序 fi 该语法结构还可以写成: if [ 条件判断式 ] then 程序

    2024年02月11日
    浏览(52)
  • Linux下的系统编程——基础操作(一)

    前言: linux系统编程是基于Linux系统进行程序开发的一个过程,主要涉及到的是linux系统中的函数使用如下图所示: 最外层的是咱们的应用程序,这部分程序大多调用的是咱们标准库,或者说是C库,这部分库函数能满足大部分的应用程序的开发,但是这部分库函数访问硬件的

    2024年02月11日
    浏览(40)
  • 【Linux操作系统】举例解释Linux系统编程中文件io常用的函数

    在Linux系统编程中,文件IO操作是非常常见和重要的操作之一。通过文件IO操作,我们可以打开、读取、写入和关闭文件,对文件进行定位、复制、删除和重命名等操作。本篇博客将介绍一些常用的文件IO操作函数。 1.1 原型、参数及返回值说明 1.1.1 原型: open()函数是Linux系统

    2024年02月12日
    浏览(48)
  • 【Linux系统编程】第九弹---权限管理操作(下)

      ✨ 个人主页:   熬夜学编程的小林 💗 系列专栏:   【C语言详解】   【数据结构详解】 【C++详解】 【Linux系统编程】 目录 1、目录权限 2、粘滞位 总结 首先提出一个问题,删除一个文件需要什么权限呢??? 回答这个问题之前我们先通过命令来看看现象。 通过上面的

    2024年04月28日
    浏览(47)
  • 【Linux操作系统】探秘Linux奥秘:shell 编程的解密与实战

    🌈个人主页: Sarapines Programmer 🔥 系列专栏: 《操作系统实验室》 🔖诗赋清音:柳垂轻絮拂人衣,心随风舞梦飞。 山川湖海皆可涉,勇者征途逐星辉。 目录 🪐1 初识Linux OS 🪐2 shell 编程的解密与实战 🌍1. 实验目的 🌍2. 实验准备 🌍3. 实验内容 🌍4. 实验心得 📝总结

    2024年02月03日
    浏览(52)
  • 基于Linux操作系统中的MySQL数据库操作(三十)

    MySQL数据库安装 目录 一、概述 (一)什么是数据库 (二)数据库能干什么     1、企业应用     2、金融行业     3、电子商务     4、社交媒体     5、物联网 (三)为什么要用数据库,优势、特性?     1、可靠性和稳定性     2、数据管理能力     3、数据共享和集成  

    2024年02月15日
    浏览(60)
  • 《Linux操作系统编程》第四章 屏幕编程器vi : 了解屏幕编辑器vi的概述和基本操作命令

    🌷🍁 博主 libin9iOak带您 Go to New World.✨🍁 🦄 个人主页——libin9iOak的博客🎐 🐳 《面试题大全》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 🌊 《IDEA开发秘籍》学会IDEA常用操作,工作效率翻倍~💐 🪁🍁 希望本文能够给您带来一定的帮助🌸文章粗浅,敬

    2024年02月11日
    浏览(68)
  • linux操作系统中的动静态库(未完)

    静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不

    2024年02月10日
    浏览(72)
  • 【Linux操作系统】深入理解系统调用中的read和write函数

    在操作系统中,系统调用是用户程序与操作系统之间进行交互的重要方式。其中,read和write函数是常用的系统调用函数,用于在用户程序和操作系统之间进行数据的读取和写入。本文将深入介绍read和write函数的工作原理、用法以及示例代码,以帮助读者更好地理解和应用这两

    2024年02月13日
    浏览(46)
  • 【Linux操作系统】Linux系统编程实现递归遍历目录,详细讲解opendir、readdir、closedir、snprintf、strcmp等函数的使用

    在Linux系统编程中,经常需要对目录进行遍历操作,以获取目录中的所有文件和子目录。递归遍历目录是一种常见的方法,可以通过使用C语言来实现。本篇博客将详细介绍如何使用C语言实现递归遍历目录的过程,并提供相应的代码示例,同时解释相关函数的使用。 1.1.1 函数

    2024年02月12日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包