Linux进程控制

目录

进程创建

fork函数初识

写时拷贝

fork常规用法

fork调用失败的原因

进程终止

终止是在做什么?

进程终止的三种情况

如何终止进程

进程等待

为什么进行进程等待

怎么进行进程等待

获取子进程status


进程创建

fork函数初识

在linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。

#include <unistd.h>

pid_t fork(void);

返回值:子进程中返回0,父进程返回子进程id,出错返回-1
进程调用fork,当控制转移到内核中的fork代码后,内核做:

  1. 分配新的内存块和内核数据结构给子进程

  2. 将父进程部分数据结构内容拷贝至子进程

  3. 添加子进程到系统进程列表当中

  4. fork返回,开始调度器调度

父进程的代码和数据是从磁盘来的,而子进程的代码和数据是没有新加载数据的,所以子进程只能用父进程的代码和数据,代码共享,数据呢以写时拷贝的方式各有一份

具体来说进程=内核的相关管理数据结构(task_struct,mm_struct,+页表)+代码和数据

是先有内核的相关管理数据结构(task_struct,mm_struct,+页表)后有代码和数据

当一个进程调用fork之后,就有两个二进制代码相同的进程。而且它们都运行到相同的地方。但每个进程都将可以 开始它们自己的旅程,看如下程序。

复制代码
int main( void )
{
 pid_t pid;
 printf("Before: pid is %d\n", getpid());
 if ( (pid=fork()) == -1 )perror("fork()"),exit(1);
 printf("After:pid is %d, fork return %d\n", getpid(), pid);
 sleep(1);
 return 0;
} 
运行结果:
[root@local linux]# ./a.out
Before: pid is 43676
After:pid is 43676, fork return 43677
After:pid is 43677, fork return 0

这里看到了三行输出,一行before,两行after。进程43676先打印before消息,然后它有打印after。另一个after 消息有43677打印的。注意到进程43677没有打印before,为什么呢?如下图所示:

所以,fork之前父进程独立执行,fork之后,父子两个执行流分别执行。注意,fork之后,谁先执行完全由调度器决定。

为什么给父进程返回子进程pid而给子进程返回0?
因为方便父进程对子进程进行标识进而进行管理。父进程有了子进程的pid可以kill或管理它,给子进程返回0正常因为是新开辟的通过0判断是否开辟成功。

写时拷贝

通常,父子代码共享,父子再不写入时,数据也是共享的,当任意一方试图写入,便以写时拷贝的方式各自一份副本。

fork常规用法

  1. 一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如,父进程等待客户端请求,生成子进程来处理请求。

  2. 一个进程要执行一个不同的程序。例如子进程从fork返回后,调用exec函数。

fork调用失败的原因

  1. 系统中有太多的进程(消耗太多内存空间)

  2. 实际用户的进程数超过了限制(每个用户的进程数是有限的,万一太多出问题)

进程终止

终止是在做什么?

  1. 其实就是释放曾经进程的代码和数据所占用的空间--释放内存

  2. 释放内核数据结构

进程终止的三种情况

a:代码跑完,结果正确

b:代码跑完,结果不正确-------代码结果正确不正确可以通过进程退出结果得出

c:代码执行时,出现异常,提前退出

异常:vs编译运行时,崩溃了--os发现你的进程做了不该做的事,os杀掉了进程。一旦出现异常,退出码就没有意义了。

进程出异常本质是因为进程收到了os发给进程的信号!

使用命令行工具如 ps、kill 或者编程接口如 waitpid 来获取进程的退出状态码和退出信号。 1. 先确认是否是异常

2. 不是异常,就一定是代码跑完了。看退出码就行

所以衡量一个进程退出,看两个数字:退出码,退出信号

0 0

!0 0

0 !0

!0 !0
四种组合

命令行中的进程都是bash的子进程。
return 0 return 100 退出码可以默认也可以自定义 错误码

如何终止进程

正常终止(可以通过 echo $? 查看进程退出码):

a. main函数return,表示进程终止(非main函数,return,函数结束)

b. 代码调用exit函数,注意:我们代码的任意位置调用exit()都表示进程退出,后面函数不跑了

c. _exit: #include <unistd.h> void _exit(int status);

虽然status是int,但是仅有低8位可以被父进程所用。所以_exit(-1)时,在终端执行$?发现返回值 是255。

进程等待

结论:任何子进程在退出的时候,一般都要被父进程等待。进程在退出的时候,如果父进程不管不顾,退出进程那么就会变成Z状态(僵尸状态),一直处于Z则会内存泄漏

为什么进行进程等待

  1. 父进程通过等待,解决子进程退出的僵尸问题,回收系统资源(一定进行的)

  2. 获取子进程的退出信息,知道子进程是因为什么原因退出的(可选的功能,可不进行)

怎么进行进程等待

wait方法:

复制代码
#include<sys/types.h>
#include<sys/wait.h>
 
pid_t wait(int*status);
 
返回值:
 成功返回被等待进程pid,失败返回-1。
参数:
 输出型参数,获取子进程退出状态,不关心则可以设置成为NULL

如果子进程没有退出,那么父进程一直在阻塞等待!等子进程状态发生变化 。

子进程本身就是软件,父进程本质是在等待某种软件就绪,那么如何理解阻塞等待子进程?其实就是阻塞等待子进程是指父进程在执行过程中,通过某种方式等待子进程执行完毕或者终止,并且在等待过程中暂停自己的执行,直到子进程退出或者产生某种事件

waitpid方法:
可指定id和-1任意进程

pid_t rid=waitpid(-1,NULL,0);是等待任何一个进程结束得到pid

id值填错会出现等待错误

  1. 如果子进程已经退出,调用wait/waitpid时,wait/waitpid会立即返回,并且释放资源,获得子进程退出信息。

  2. 如果在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞。

  3. 如果不存在该子进程,则立即出错返回。

获取子进程status

  1. wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。

  2. 如果传递NULL,表示不关心子进程的退出状态信息。

  3. 否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。

  4. status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特 位):

子进程退出要得到两个信息:进程退出码,推出信号。

一个status是32位的,但是我们只考虑低16位

退出码:(status>>8)&0xFF

推出信号:status&0x7F

WIFEXITED(status):程序正常运行完无异常信号

WEXITSTATUS(status):查看退出码

先看有无异常再看退出码

父进程等待是必须的,获得子进程的退出信息不是必须的所以status可以为NULL
阻塞等待:如果子进程没有退出,而父进程在执行waitpid进行等待,那么会一直卡在waitpid那里因为子进程没退 --叫做阻塞等待。比如平常使用的接口scanf,cin,cout等都会涉及一些。

阻塞本质就是进程不被调度不在运行队列里面,pcb在等待队列里面,在等待某种条件发生(子进程退出)。父进程什么都没干只是在等。所以waitpid的options值位0代表阻塞等


**非阻塞等待:**非阻塞等待是指在等待某个事件发生时,不会使程序陷入阻塞状态,而是会立即返回,允许程序继续执行其他任务或轮询事件。

可以使用 waitpid() 函数实现非阻塞等待子进程退出。通过传入 WNOHANG 选项,waitpid() 函数可以在没有可等待的子进程退出时立即返回,而不会阻塞当前进程。

pid_t>0:等待成功,子进程退出了,并且父进程回收成功

pid_t<0:等待失败

pid_t==0:检测是成功的,只不过子进程没退出,需要你下一次继续进行重复等待

非阻塞等待的时候+循环=非阻塞轮询------允许父进程做一些其他的事情

相关推荐
skywalk81634 小时前
在FreeBSD系统的linux仿真环境下安装和使用kiro 这个亚马逊的AI agent
linux·人工智能·freebsd·kiro
Mikko74 小时前
Linux 磁盘满了但 du 找不到?LVM 扩容 df 不变?fstab 写错开不了机?三台真机实测磁盘排查
linux·运维·centos
蓝胖的四次元口袋4 小时前
Jenkins知识梳理(2)
运维·jenkins
yumgpkpm4 小时前
Acceldata ODP 3.3.6.4 vs CDP Private Cloud Base 7.3.2 对比
大数据·运维·服务器·hadoop·华为·zookeeper·hbase
Madison-No74 小时前
多语言聊天大模型--测试报告
linux·git·python·selenium·jmeter·自动化·postman
Liuqy-054 小时前
特殊进程——孤儿、僵尸、守护进程
linux·运维·服务器
流浪0014 小时前
Linux系统篇47——线程(十二) POSIX 信号量与环形队列,把判空判满提前到访问之前
linux·操作系统·线程·信号量·环形队列
咖丨喱5 小时前
【MMC Core + hc16 Host(WiFi SDIO 如何落到控制器)】
linux
等我调个Bug5 小时前
【Linux系统篇】权限
linux·服务器
考研保研资料分享5 小时前
自动化控制保研经验合辑:上交夏令营、北工大预推免与跨专业面试复盘(2025)
运维·面试·自动化