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

Linux(十)僵死进程及文件操作

一、僵死进程(僵尸进程)

(一)僵死进程产生的原因(条件)

其实,僵死进程的定义也就是它的产生原因(条件),让我们一起了解一下吧!

当子进程先于父进程结束,父进程没有获取子进程的退出码,此时子进程变成僵死进程。(这句话非常重要!!!)

我们来进一步了解一下:

1、退出码:(举个例子)exit(0)中的0就是退出码,表示正常退出。

2、用我们自己的话解释僵死进程就是:不是就绪、阻塞、运行(进程的三个基本状态)的进程就是僵死进程。

3、在有父、子进程的情况下,正常删除子进程的步骤:(1)先释放子进程的实体(2)将子进程的退出码赋值为0(3)父进程获取子进程的退出码(4)删除子进程的PCB(也就是进程控制块)

简而言之,就是子进程先结束,并且父进程没有获取它的退出码;

那么僵死进程产生的原因或者条件就是:子进程先于父进程结束,并且父进程没有获取子进程的退出码;

(二)僵死进程的产生过程

让我们通过图片更加清楚的了解产生过程吧

 

上面的图片从左到右、从上到下分别为初始、1、2、3步,产生僵死进程则就出现在第三步

(三)观察僵死进程

让我们通过代码一起来观察一下僵死进程,用到的代码我放在下面啦!

#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <stdlib.h>
 
int main(){
    char *s=NULL;
    int n=0;//控制父子进程执行的次数;
 
    pid_t id=fork();
    assert(id !=- 1);
 
    if(id == 0){
        s="child";
        n=3;
    }//子进程
    
    else{
        s="parent";
        n=7;
    }//父进程
    //父子进程
    int i=0;
    for(;i<n;i++){
        printf("s=%s\n",s);
        sleep(1);//是因为两个进程同时打印太快了,一下就出来感受不到,sleep后就感觉到同时
    }
    exit(0);
}
 

在上面这个代码中,子进程执行3次,父进程执行7次,就能观察到僵死进程

 在上述我提供的截图可以看待,[test]的后面出现了<defunct>这就是指僵死进程。

(四)处理僵死进程的意义

也就是僵死进程的坏处:白白消耗内存

在《Linux内核设计与实现》27页有这样的描述

(五)处理僵死进程的两种方法

通过定义我们了解到僵死进程的产生原因,那么我们从产生原因入手就可以得到处理僵死进程的两种方法:(1)父进程先结束(2)父进程调用wait()方法获取子进程的退出码

1、父进程先结束

在上述代码中,我们将子进程改为10,父进程改为3,就会发现没有僵死进程,这是因为父进程已经结束,子进程变成了孤儿进程(这个名词非常生动,意思就是没有父进程的子进程就是孤儿),孤儿进程会被收养

我们将代码中父子进程部分修改一下,打印出PID和PPID

for(;i<n;i++){
        printf("s=%s\n,pid=%d,ppid=%d\n",s,getpid(),getppid());
        sleep(1);//是因为两个进程同时打印太快了,一下就出来感受不到,sleep后就感觉到同时
    }

我们就会发现下图中找到的结果 

2、父进程调用wait()方法获取子进程的退出码

在第二种方法中,我们看到了一个新的函数wait(),让我们使用帮助手册查看一下使用方法(man 2 wait,不能是man wait,因为此时帮助手册上的wait(1)是指命令,而不是库函数)

在这里,我们将代码的父进程部分进行修改,可以让我们看到退出码

修改后运行,会发现我在图片中标注的内容

我们通常也会这样使用wait(),下图这样也是可以的

        让我们一起总结一下,两种处理方法的本质其实是一样的,都调用了wait获取子进程退出码方法一是父进程先结束后子进程被Init(现在随着内核的发展不一定是1)收养,Init之后调用wait获取子进程退出码;方法二是父进程直接调用wait()但是两种方法又有区别,就是父进程调用wait会阻塞,等子进程执行完之后,父进程才会执行。

        若想父进程调用wait不阻塞,那么我们需要结合信号一起,后面小编会在学习信号时向大家介绍。

(补充:退出码)

小编在这里还想带大家了解一下退出码

我们将上面调用wait的代码中的exit(0)改为exit(3);

然后执行

就会发现退出码变成了768,这其实也就是3的意思。

二、文件操作

(一)Linux操作文件的底层系统调用

在C语言中,我们曾学习过几个库函数,分别是fopen,fread,fwrite,fclose;

那么,在系统调用中则是open,read,write,close;系统调用的方法是实现在内核中的(陷入内核,切换到内核)

(二)open、write、read、close详细介绍

1、open的介绍

首先,让我们使用man 2 open打开帮助手册

open的重载,两个参数用于打开一个已经存在的文件三个参数的用于新建一个文件并设置访问权限;

pathname:文件的路径和名称;
flags:文件的打开方式;
mode:文件的权限,如"0600”;

open的返回值为int,称为文件描述符;

文件描述符:文件打开以后,内核给文件的一个编号;(>0的整数)

open的返回值是int,称之为“文件描述符”;每打开一个文件,我们就会得到一个文件描述符,这个文件描述符是一个整型,通过文件描述符就可以对文件进行读写这样的操作.open失败返回-1,成功返回一个大于等于0的值;0,1,2是默认打开的;

flags的打开标志,如:(下面都是常用的)
O_WRONLY:只写打开;
O_RDONLY:只读打开;
O_RDWR:读写方式打开;
O_CREAT:文件不存在则创建;
O_APPEND:文件末尾追加;
O_TRUNC:清空文件,重新写入;

(下面三个函数都需要查看帮助手册,这里我就不展示了,希望大家可以在练习时自己学会查看帮助手册) 

2、write的介绍

fd:对应打开的文件描述符
buf:写入的文件内容;
count:要写入多少个字节;
返回值:ssize_t:实际写入了多少个字节;

3、read的介绍

fd:对应打开的文件描述符;
buf:把文件内容读取到一块空间buf中;
count:期望要读取的字节数;
返回值:ssize_t:实际读取了多少个字节;

4、close的介绍

关闭文件描述符;

练习:

#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <stdlib.h>
#include<fcntl.h>
int main(){
   //write(1,"hello",5);
   //int fd = open("file.txt",O _WRONLY|O_CREAT,0600);//不写路径就是当前路径
   int fd = open("file.txt",O_RDONLY);//不写路径就是当前路径
   assert(fd!=-1);//这一句特别重要,因为有可能出现路径或文件名写错
   printf("fd=%d",fd);
   write(fd,"hello",5);
   char buff[128]={0};
   int n= read(fd,buff,127);
   printf("n=%d,buff=%s\n",n,buff);
   close(fd);
   exit(0);
}

大家可以根据上述代码进行练习,也可以尝试使用读写复制文件。

【小编有话说】今天的内容就要结束啦,今天也是干活满满的一篇文章呢!大家一定要和小编一起练习呀,自己动手才是最重要的呢!!!

最后还是老三样,点赞收藏和关注~

喜欢小编的文章就不要忘记这三样,毕竟点赞收藏关注,找到小编不迷路~


http://www.kler.cn/a/610705.html

相关文章:

  • 【后端开发面试题】每日 3 题(二十一)
  • Linux实现生产者消费者模型
  • css重点知识汇总(二)
  • 网络华为HCIA+HCIP 广域网技术
  • ffmpeg-将多个视频切片成一个新的视频
  • Azure SDK 使用指南
  • 破解PDF转Word难题:如何选择高效、安全的转换工具?
  • 多版本PHP开发环境配置教程:WAMPServer下MySQL/Apache/MariaDB版本安装与切换
  • Photoshop怎样保存为ico格式
  • 【QT】QT中的中文显示乱码解决
  • 机器人的手眼标定——机器人抓取系统基础系列(五)
  • Docker 命令分类整理
  • AXIOM —— 安装
  • 无人机数据链技术详解,无人机图传数传技术,无人机数据传输技术原理
  • 网络华为HCIA+HCIP 路由
  • Day16 -实例:Web利用邮箱被动绕过CDN拿真实ip
  • Git基础理论知识学习笔记
  • Qt信号槽函数
  • uv - Getting Started 开始使用 [官方文档翻译]
  • Linux笔记---动静态库(使用篇)