当前位置: 首页 > news >正文

Linux之进程控制

目录

进程创建

fork()

进程终止

1.进程退出的场景

2.查看进程退出码的命令

3.进程退出的方法

进程等待

1.为什么要进行进程等待?

2.如何进行进程等待?

进程替换

1.进程替换概念:

2.进程替换原理:

3.进程替换的接口--exec*函数系列


进程创建

fork()

1.函数介绍:pid_t fork();fork函数用于创建子进程,若是创建成功,在子进程中返回0,在父进程返回新创建的子进程的id,若是创建失败,返回-1

2.调用fork函数,内核会做什么?

<1>分配资源:

1)控制进程快:内核为新创建的子进程分配一个新的 task_struct 结构体,这是进程在内核中的核心数据结构,用于存储进程的所有信息,如进程ID、状态、内存映射、文件描述符等。

2)内存空间:为子进程分配必要的内存空间,包括用户态的内存(如栈、堆)和内核态的内存

<2>复制父进程的代码和数据:

1)复制代码段、数据段、堆和栈:内核将父进程的代码段、数据段、堆和栈的内容复制到子进程中。但为了提高效率,现代Linux内核采用了写时复制(Copy-on-Write, COW)技术。这意味着在 fork() 时,实际上并没有立即复制数据,而是让父子进程共享相同的物理内存页。只有当某个进程尝试修改这些共享的内存页时,才会触发缺页异常,内核才会为修改的进程创建这些内存页的副本。

2)复制文件描述符表:复制父进程的文件描述符表,使得父子进程可以共享打开的文件。但是,每个文件描述符的引用计数会增加,以反映它被两个进程共享。

<3>初始化子进程:

1)为新创建的子进程分配一个唯一的进程ID。

2)将子进程的状态设置为不可中断睡眠状态(TASK_UNINTERRUPTIBLE),以确保在子进程完成初始化之前不会被调度执行。

<4>设置父子关系:

1)在父进程的 task_struct 中添加对新创建的子进程的引用。

2)在子进程的 task_struct 中设置父进程的引用,以及指向父进程进程组的指针

<5>执行调度:

1)内核将子进程添加到系统的进程列表中,准备进行调度。

2)返回值

3.fork函数可以有两个返回值,这是为什么呢?

答案是在进行程序调度时发生写实拷贝,子进程和父进程共享大部分的数据和代码,当执行子进程时,在物理内存上对子进程的代码和数据进行拷贝,在另一块物理内存上执行,同理执行父进程时也是如此,故而父进程和子进程在执行时实际上是两个独立的进程,每个进程都会接收fork的返回值

补充:写实拷贝

<1>概念:写实拷贝是一种内存管理策略,其核心思想是:在多个进程或线程共享同一块内存区域时,如果不进行写操作,则这些进程或线程可以共享同一块物理内存;一旦某个进程或线程尝试对共享内存区域进行写操作,操作系统会为该进程或线程分配一块新的物理内存,并将原共享内存区域的内容复制到新的内存中,以确保数据的一致性和独立性。

<2>原理:

写实拷贝技术通常通过引用计数来实现。在分配共享内存区域时,系统会多分配一些空间来存储引用计数,用于记录有多少个进程或线程正在共享这块内存。当某个进程或线程尝试对共享内存进行写操作时,系统会先检查引用计数:

***如果引用计数大于1,说明有其他进程或线程也在共享这块内存,此时系统会为该进程或线程分配一块新的物理内存,并将原共享内存的内容复制到新内存中,然后将引用计数减1。

***如果引用计数等于1,说明没有其他进程或线程在共享这块内存,此时可以直接对该内存进行写操作,无需复制。

<3>好处:提高性能,简化内存管理

进程终止

1.进程退出的场景

<1>代码运行完毕,结果正确

<2>代码运行完毕,结果不正确

<3>代码异常终止

注:若代码运行完毕,结果正确与否是通过进程退出码判断的;若进程异常终止,此时进程退出码无意义,而进程出现异常,往往是进程接收了信号

2.查看进程退出码的命令

. echo $? :此命令用于打印最近一个程序/进程退出时的退出码(因为进程退出码会被写在进程的task_struct内部)

3.进程退出的方法

<1>在main函数内部写return

<2>使用exit(进程退出码)函数,在任何地方调用exit(),进程会结束,同时将子进程的进程退出码返回给父进程

<3>使用_exit(进程退出码)函数

exit_exit
头文件<stdlib.h><unistd.h>
是否进行缓冲区刷新
返回值将代表退出状态的整数返回将代表退出状态的整数返回

注:exit函数底层封装了_exit函数

进程等待

1.为什么要进行进程等待?

答案是通过等待,解决内存泄漏问题,回收子进程资源;获取子进程的退出信息

2.如何进行进程等待?

<1>pid_t wait(int* status);

1)功能:使父进程等待任意一个子进程结束,并获取子进程的终止状态

2)头文件:<sys/wait.h>

3)参数解释:status:一个指向整数的指针,用于存储子进程的终止状态。如果不需要这个信息,可以传递 NULL

4)返回值:成功返回子进程的id;失败返回-1,并设置errno指示错误信息

<2>pid_t waitpid(pid_t pid,int* status,int options);

1)功能:使父进程等待特定子进程结束,设置是否阻塞父进程模式,并获取子进程的终止状态

2)头文件:<sys/wait.h>

3)参数解释:

pid:指定要等待的子进程的进程 ID

>0等待进程 ID 等于 pid 的子进程
=0等待与调用进程属于同一个进程组的任意子进程
<-1等待进程组 ID 等于 pid 绝对值的任意子进程
=-1等待任意一个子进程,此时 waitpid 的行为与 wait 类似

status:指向整数的指针,用于存储子进程的终止状态。如果不需要这个信息,可以传递 NULL

options:设置是否阻塞,默认为0

WNOHANG如果没有子进程结束,则立即返回 0,而不是阻塞等待。这允许父进程以非阻塞的方式检查子进程的状态
WUNTRACED除了等待终止的子进程外,还等待被暂停(stopped)的子进程

4)返回值:

>0说明等待结束,返回子进程的id;

=0说明调用结束,但是子进程没有退出;

<0说明等待失败,并设置errno指示错误信息

进程替换

1.进程替换概念:

进程替换允许一个进程在运行过程中被另一个新的进程完全替换,在进程替换发生时,原有进程的代码、数据和资源会被新的进程所取代,新进程开始执行,原有进程的执行状态和上下文信息会被丢弃。

2.进程替换原理:

父进程通过fork函数创建子进程,子进程内部调用exec*系列函数来执行新进程。exec 系列函数不会创建新进程,而是直接用新程序替换当前进程的内容,一旦替换完成,后续代码将不在执行。调用 exec 函数后,当前进程的代码和数据完全被新程序替换,从新程序的启动例程(通常是 main 函数)开始执行。尽管进程的代码和数据被替换了,但进程的 ID(PID)、父进程 ID(PPID)、文件描述符等关键信息会被保留。在进程替换之后,父进程仍然可以通过原来的 PID 来等待子进程的结束

3.进程替换的接口--exec*函数系列

<1>int execl(const char* path,const char* arg,...);

直接接受参数列表和环境变量(或继承当前环境变量)

<2>int execlp(const char* file,const char* arg,...);

接受程序名而不是路径,并使用PATH环境变量来查找程序

<3>int execv(const char* path,const char* argv[]);

接受参数列表作为数组,并继承当前环境变量。

<4>int execvp(const char* file,const char* argv[]);

类似于execv,但接受程序名并使用PATH环境变量查找。

<5>int execvpe(const char* file,const char* argv[],char* const envp[]);

1)参数解释:

path:路径+程序名,用于解释我要执行什么

file:要执行的文件名(因为会自动在环境变量PATH中查找指定命令)

arg:可变参数列表,命令行怎么写,我就怎么写,最后要以NULL结尾

argv[]:参数列表数组,第一个元素是程序名,最后一个元素是NULL

envp[]:存放环境变量的指针数组列表

2)返回值:成功不返回任何东西;失败返回-1,并设置errno指示错误信息

3)若要将新的环境变量添加到子进程内?

方法一:使用putenv(),在哪个进程调用它,就在哪个进程新增环境变量

方法二:使用extern char** environ;声明,再调用execvpe(file,argv[],envp[],environ)函数

相关文章:

  • HTML5-基础知识
  • CentOS 6 YUM源切换成国内yum源
  • 适合企业内训的AI工具实操培训教程(37页PPT)(文末有下载方式)
  • 优艾智合加码具身智能赛道,“一脑多态”技术矩阵率先规模化落地
  • vue3 中使用 Recorder 实现录音并上传,并用Go语言调取讯飞识别录音(Go语言)
  • HAL库STM32常用外设—— CAN通信(一)
  • JVisualVM 监控线程池状态
  • Word 小黑第27套
  • STC89C52单片机学习——第13节:[5-1]模块化编程
  • SSL 原理及实验
  • Xxl-Job学习笔记
  • linux root丢失修改密
  • Python XML 解析
  • STC89C52单片机学习——第11节:[4-1]静态数码管显示
  • el-table 插槽踩过的坑 :slot-scope 和#default的区别
  • 【C#学习】协程等待
  • UI基础概念+Canvas相关知识
  • 24 浅谈模块
  • 用户数据报协议(User Datagram Protocol,UDP)
  • 学习MDA规范_9.CORBA(公共对象请求代理架构)‌
  • 国务院关税税则委员会公布公告调整对原产于美国的进口商品加征关税措施
  • SIFF动画单元公布首批片单:《燃比娃》《凡尔赛玫瑰》等
  • 中美是否计划讨论美方以芬太尼为由对华征收的特别关税?外交部回应
  • 上海现有超12.3万名注册护士,本科及以上学历占一半
  • 国家统计局今年将在全国开展两次人口固定样本跟访调查
  • 重庆荣昌区委区政府再设“答谢宴”,邀请800余名志愿者机关食堂用餐