【进程控制(进程退出、孤儿进程、僵尸进程)_Linux】

2024-02-11 08:18

本文主要是介绍【进程控制(进程退出、孤儿进程、僵尸进程)_Linux】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        • 01 / 进程退出
        • 02 / 孤儿进程
        • 03 / 僵尸进程
        • 04 / 进程回收
          • wait()函数
          • 退出信息相关宏函数
          • waitpid()函数

01 / 进程退出
//标准C库函数
#include <stdlib.h>
void exit(int status);//Linux系统函数
#include <unistd.h>
void _exit(int status);//status参数:是进程退出时的一个状态信息。父进程回收子进程资源的时候可以获取到。

在这里插入图片描述
示例

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main() {printf("hello\n");printf("world");// exit(0);_exit(0);return 0;
}
02 / 孤儿进程

父进程运行结束,但子进程还在运行(未运行结束),这样的子进程就称为孤儿进程(Orphan Process)。

◼ 每当出现一个孤儿进程的时候,内核就把孤儿进程的父进程设置为 init ,而 init 进程会循环地 wait() 它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init 进程就会代表党和政府出面处理它的一切善后工作。

◼ 因此孤儿进程并不会有什么危害。

示例

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>int main() {// 创建子进程pid_t pid = fork();// 判断是父进程还是子进程if(pid > 0) {printf("i am parent process, pid : %d, ppid : %d\n", getpid(), getppid());} else if(pid == 0) {sleep(1);// 当前是子进程printf("i am child process, pid : %d, ppid : %d\n", getpid(),getppid());}// for循环for(int i = 0; i < 3; i++) {printf("i : %d , pid : %d\n", i , getpid());}return 0;
}

在这里插入图片描述

03 / 僵尸进程

◼ 每个进程结束之后, 都会释放自己地址空间中的用户区数据,内核区的 PCB 没有办法自己释放掉,需要父进程去释放。

进程终止时,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸(Zombie)进程。

僵尸进程不能被 kill -9 杀死这样就会导致一个问题,如果父进程不调用 wait() 或 waitpid() 的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程,此即为僵尸进程的危害,应当避免。

示例

在这里插入图片描述
在这里插入图片描述

04 / 进程回收

◼ 在每个进程退出的时候,内核释放该进程所有的资源、包括打开的文件、占用的内存等。但是仍然为其保留一定的信息,这些信息主要主要指进程控制块PCB的信息(包括进程号、退出状态、运行时间等)。

◼ 父进程可以通过调用wait或waitpid得到它的退出状态同时彻底清除掉这个进程。

◼ wait() 和 waitpid() 函数的功能一样,区别在于,wait() 函数会阻塞,waitpid() 可以设置不阻塞,waitpid() 还可以指定等待哪个子进程结束。

◼ 注意:一次wait或waitpid调用只能清理一个子进程,清理多个子进程应使用循环。

wait()函数
   #include <sys/types.h>#include <sys/wait.h>pid_t wait(int *wstatus);功能:等待任意一个子进程结束,如果任意一个子进程结束了,次函数会回收子进程的资源。参数:int *wstatus进程退出时的状态信息,传入的是一个int类型的地址,传出参数。返回值:- 成功:返回被回收的子进程的id- 失败:-1 (所有的子进程都结束,调用函数失败)调用wait函数的进程会被挂起(阻塞),直到它的一个子进程退出或者收到一个不能被忽略的信号时才被醒(相当于继续往下执行)如果没有子进程了,函数立刻返回,返回-1;如果子进程都已经结束了,也会立即返回,返回-1.
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>int main() {// 有一个父进程,创建5个子进程(兄弟)pid_t pid;// 创建5个子进程for(int i = 0; i < 5; i++) {pid = fork();if(pid == 0) {break;}}if(pid > 0) {// 父进程while(1) {printf("parent, pid = %d\n", getpid());// int ret = wait(NULL);int st;int ret = wait(&st);if(ret == -1) {break;}if(WIFEXITED(st)) {// 是不是正常退出printf("退出的状态码:%d\n", WEXITSTATUS(st));}if(WIFSIGNALED(st)) {// 是不是异常终止printf("被哪个信号干掉了:%d\n", WTERMSIG(st));}printf("child die, pid = %d\n", ret);sleep(1);}} else if (pid == 0){// 子进程while(1) {printf("child, pid = %d\n",getpid());    sleep(1);       }exit(0);}return 0; // exit(0)
}
退出信息相关宏函数
WIFEXITED(status)0,进程正常退出
◼ WEXITSTATUS(status) 	如果上宏为真,获取进程退出的状态(exit的参数)◼ WIFSIGNALED(status)0,进程异常终止
◼ WTERMSIG(status) 		如果上宏为真,获取使进程终止的信号编号◼ WIFSTOPPED(status)0,进程处于暂停状态
◼ WSTOPSIG(status) 		如果上宏为真,获取使进程暂停的信号的编号
◼ WIFCONTINUED(status)0,进程暂停后已经继续运行
waitpid()函数
    #include <sys/types.h>#include <sys/wait.h>pid_t waitpid(pid_t pid, int *wstatus, int options);功能:回收指定进程号的子进程,可以设置是否阻塞。参数:- pid:pid > 0 :   某个子进程的pidpid = 0 :   回收当前进程组的所有子进程    pid = -1 :  回收所有的子进程,相当于 wait()  (最常用)pid < -1 :  某个进程组的组id的绝对值,回收指定进程组中的子进程- options:设置阻塞或者非阻塞0 :         阻塞WNOHANG :   非阻塞- 返回值:> 0 :       返回子进程的id= 0 :       options=WNOHANG, 表示还有子进程或者= -1 :     错误,或者没有子进程了
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>int main() {// 有一个父进程,创建5个子进程(兄弟)pid_t pid;// 创建5个子进程for(int i = 0; i < 5; i++) {pid = fork();if(pid == 0) {break;}}if(pid > 0) {// 父进程while(1) {printf("parent, pid = %d\n", getpid());sleep(1);int st;// int ret = waitpid(-1, &st, 0);int ret = waitpid(-1, &st, WNOHANG);if(ret == -1) {break;} else if(ret == 0) {// 说明还有子进程存在continue;} else if(ret > 0) {if(WIFEXITED(st)) {// 是不是正常退出printf("退出的状态码:%d\n", WEXITSTATUS(st));}if(WIFSIGNALED(st)) {// 是不是异常终止printf("被哪个信号干掉了:%d\n", WTERMSIG(st));}printf("child die, pid = %d\n", ret);}}} else if (pid == 0){// 子进程while(1) {printf("child, pid = %d\n",getpid());    sleep(1);       }exit(0);}return 0; 
}

这篇关于【进程控制(进程退出、孤儿进程、僵尸进程)_Linux】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/699318

相关文章

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删

Windows的CMD窗口如何查看并杀死nginx进程

《Windows的CMD窗口如何查看并杀死nginx进程》:本文主要介绍Windows的CMD窗口如何查看并杀死nginx进程问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录Windows的CMD窗口查看并杀死nginx进程开启nginx查看nginx进程停止nginx服务

Linux链表操作方式

《Linux链表操作方式》:本文主要介绍Linux链表操作方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、链表基础概念与内核链表优势二、内核链表结构与宏解析三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势六、典型应用场景七、调试技巧与

详解Linux中常见环境变量的特点与设置

《详解Linux中常见环境变量的特点与设置》环境变量是操作系统和用户设置的一些动态键值对,为运行的程序提供配置信息,理解环境变量对于系统管理、软件开发都很重要,下面小编就为大家详细介绍一下吧... 目录前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变

Linux系统中的firewall-offline-cmd详解(收藏版)

《Linux系统中的firewall-offline-cmd详解(收藏版)》firewall-offline-cmd是firewalld的一个命令行工具,专门设计用于在没有运行firewalld服务的... 目录主要用途基本语法选项1. 状态管理2. 区域管理3. 服务管理4. 端口管理5. ICMP 阻断

Linux实现线程同步的多种方式汇总

《Linux实现线程同步的多种方式汇总》本文详细介绍了Linux下线程同步的多种方法,包括互斥锁、自旋锁、信号量以及它们的使用示例,通过这些同步机制,可以解决线程安全问题,防止资源竞争导致的错误,示例... 目录什么是线程同步?一、互斥锁(单人洗手间规则)适用场景:特点:二、条件变量(咖啡厅取餐系统)工作流

Python远程控制MySQL的完整指南

《Python远程控制MySQL的完整指南》MySQL是最流行的关系型数据库之一,Python通过多种方式可以与MySQL进行交互,下面小编就为大家详细介绍一下Python操作MySQL的常用方法和最... 目录1. 准备工作2. 连接mysql数据库使用mysql-connector使用PyMySQL3.

Linux中修改Apache HTTP Server(httpd)默认端口的完整指南

《Linux中修改ApacheHTTPServer(httpd)默认端口的完整指南》ApacheHTTPServer(简称httpd)是Linux系统中最常用的Web服务器之一,本文将详细介绍如何... 目录一、修改 httpd 默认端口的步骤1. 查找 httpd 配置文件路径2. 编辑配置文件3. 保存

Linux使用scp进行远程目录文件复制的详细步骤和示例

《Linux使用scp进行远程目录文件复制的详细步骤和示例》在Linux系统中,scp(安全复制协议)是一个使用SSH(安全外壳协议)进行文件和目录安全传输的命令,它允许在远程主机之间复制文件和目录,... 目录1. 什么是scp?2. 语法3. 示例示例 1: 复制本地目录到远程主机示例 2: 复制远程主

Java进程CPU使用率过高排查步骤详细讲解

《Java进程CPU使用率过高排查步骤详细讲解》:本文主要介绍Java进程CPU使用率过高排查的相关资料,针对Java进程CPU使用率高的问题,我们可以遵循以下步骤进行排查和优化,文中通过代码介绍... 目录前言一、初步定位问题1.1 确认进程状态1.2 确定Java进程ID1.3 快速生成线程堆栈二、分析