#每日Linux小练习#12进程的详细分析

经常被问到进程和线程的区别,今天对进程进行详细的分析讨论。

一、进程的定义

进程是操作系统的概念,每当我们执行一个程序时,对于操作系统来讲就创建了一个进程,在这个过程中,伴随着资源的分配和释放。可以认为进程是一个程序的一次执行过程。

二、进程与程序的区别

程序时静态的,它是一些保存 在磁盘上得指令的有序集合,没有任何执行的概念。

进程是一个动态的概念,它是程序执行的过程,包括创建、调度和消亡。

三、linux系统中进程的表示

在linux系统中,进程由一个叫task_struct的结构体描述,也就是说linux中的每个进程对应一个task_struct结构体。该结构体记录了进程的一切。下面我们来看看它的核心字段。

struct task_struct
{
    //这个是进程的运行状态,-1代表不可运行,0代表可运行,>0代表已经停止。
    volatile long state;
    /*
        flags是进程当前的状态标志,具体如下:
        0x0002表示进程正在被创建
        0x0004表示进程正准备退出
        0x0040表示此进程被fork出,但是并没有执行exec
        0x0400表示此进程由于其他进程发送相关信号而被杀死
    */
    unsigned int flags; //反应进程状态的信息,但不是运行状态

    //表示此进程的运行优先级
    unsigned     int   rt_priority;

    //该结构体记录了进程内存使用的相关情况
    struct   mm_struct *mm;

    //进程号,是进程的唯一标识
    pid_t   pid;

    //进程组号
    pid_t  tgid;

    //real_parent是该进程的"亲生父亲",不管其是否被"寄养"//该指针指向创建当前进程的的进程,或者是当创建者已经消亡后,该指针指向init进程。
    struct  task_struct  *real_parent;
    //parent是该进程现在的父进程,有可能是"继父"//一般情况下和real_parent一样,只是当另外一个进程调用了ptrace()系统调用后
    struct   task_struct  *parent;

    //这里children指的是该进程孩子的链表,可以得到所有孩子的进程描述符
    struct   list_head    children;

    //同理,sibling该进程兄弟的链表,也就是其父进程的所有孩子的链表
    struct    list_head    sibling;

    //这个是主线程的进程描述符,也许你会奇怪,为什么线程用进程描叙符表示,因为linux并没有单独实现线程的相关结构体,只用一            个进程来代替线程,然后对其做一些特殊的处理。
    struct   task_struct  *group_leader;

    //这个是该进程所有线程的链表
    struct   list_head   thread_group;

    //这个是该进程使用cpu时间的信息,utime是在用户态下执行的时间,stime 是在内核态下执行的时间
    cputime_t   utime,stime;

    //comm是保存该进程名字的字符数组,长度最长为15,因为TASK_COMM_LEN为16
    char   comm[TASK_COMM_LEN];

    //打开的文件相关信息结构体
    struct  files_struct  *files;

    //信号相关信息的句柄
    struct   signal_struct  *signal;
    struct   sigband_struct  *sighand;

};

四、linux进程中的文件

linux操作系统中每个进程有两个数据结构描叙文件相关信息

第一个:fs_struct,它包含此进程当前工作目录和根目录、umask。umask是新文件被 创建的缺省模式,它可以通过系统调用来改变。

第二个:files_struct,包含此进程正在使用的所有文件的信息。f_mode字段描述该文件是以什么模式创建的:只读、读写、还是只写。f_pos保存文件中下一个读或写将发生的位置。f_inode描叙文件的VFS索引节点,而f_ops是一个例程向量的指针,每个代表一个想施加于文件的操作的函数。

每次一个文件被打开时,files_struct中的空闲file指针之一就被用来指向新的file结构。Linux进程在启动时有三个文件描叙符被打开了,他们是标准输入设备、标准输出设备和标准错误设备,并且通常是从创建此进程的父进程继承得来的。所有对文件的访问时通过传递或返回文件描叙符的标准系统调用进行的。这些描述符是进程fd向量的索引,所以标准输入设备、标准输出设备和标准错误设备分别对应文件描述符0、1和2。

五、进程中的虚拟内存

在Linux操作系统中,当我们运行一个二级制可执行文件时,操作系统将创建一个进程。此时如果将这个可执行二进制文件的全部代码和数据装入物理内存将是浪费的。因为他们不可能同时使用。随着系统中进程数的增多,这种浪费将被成倍的扩大,系统将非常低效地运行。事实上,linux使用一种称为请求调页(demand-paging)的技术:只有当进程要使用时其虚拟内存时,其对应的数据才装入物理内存。所以,不是直接把代码和数据装入物理内存。linux内核只修改进程的页表,标识虚拟内存页存在但其对应的数据不在内存中。当进程想要访问代码或数据时,系统硬件将产生页故障并把控制交给Linux内核来解决。因此,对于进程地址空间中的每一个内存区,Linux都需要知道该虚拟内存来自何处,以及如何把它装入内存以解决故障。

当一个进程分配虚拟内存时,Linux并不真正为它保留物理内存。它只是创建一个新vm_area_struct数据结构来描叙虚拟内存,这个结构被链入进程的虚拟内存列表。当进程试图写一个位于新分配虚拟内存区域的虚拟地址时,系统将产生页故障。处理器试图转换该虚拟地址,但是因为没有此内存的页表项,它将放弃并产生一个页故障异常,留给Linux内核来解决。Linux查看被引用的虚拟地址是否是位于当前进程的虚拟内存地址空间。

  如果是,Linux创建适当的PTE并为此进程分配一页物理内存。代码或数据可能需要从文件系统或交换硬盘上读入物理内存。然后进程可以从引起页故障的那条指令处重启,并且因为这次内存物理地址存在,所以它可以继续执行。

如果不是,就是大家常常见到的"段错误"。

下面来用一个程序加深对进程的了解,与上面的理论内容关系不是非常紧密,只是想说明进程创建的相互关系。

程序./20150814pstree.sh

./20150814pstree_sleep.sh &

pstree -Aup ubuntu| grep -n -A2 -B3 ‘sh‘
while [ 0 ]
do
    sleep 2
done

程序./20150814pstree_test.sh

echo "this is $0 ,my PID is $$"
while [ 0 ]
do
#    echo "3s has passed"
    sleep 3
done

Step1:程序运行结果如下:

gonme-terminal(2805)是本图形界面tty7对应的终端程序,tty7下使用bash(2810)运行了20150814pstree.sh(3263)这个进程。

20150814pstree.sh(3263)这个进程又运行了20150814pstree_sleep.sh(3622)这个进程,grep进程,pstree进程

Step2:在原有基础上再开一个窗口(相当于一个bash文件),再次运行20150814pstree.sh程序,

可以看出,多出了bash(3739)这个进程,对应新打开的窗口,之后的20150814pstree.sh(3976)进程,以及其子进程同上面的解释

Step3:此时,将先前的窗口关闭,在新窗口中重新运行20150814pstree.sh程序,

1、bash(3739)的进程号不变

2、20150814pstree.sh的进程号变化了(因为是新的)

3、之前的窗口被关闭了,所以对应的进程消失了,然而它的子进程也消失了

Step4:

此时,键入  ps -l  命令

来分析一下,

bash(3739)->20150814pstree.sh(4533)->sleep(5850)

                    ->20150814pstree_sleep.sh(4534)->sleep(5848)

      ->ps(5987)

init(1)->20150814pstree_sleep.sh(3918)->sleep(5987)

->20150814pstree_sleep.sh(3977)->sleep(5986)

在前一个窗口中,使用CRTL+C关闭了20150814pstree.sh,而对应的后台运行的子进程20150814pstree_sleep.sh都没有管,成为了“僵尸”进程,就归init管了。

这时候,可以使用kill 指令将其关闭。

本文中代码可以从github上面下载,https://github.com/yifeng152/oneShellPracticePerDay.git

对应文件为20150814pstree.sh

时间: 2024-12-17 04:29:27

#每日Linux小练习#12进程的详细分析的相关文章

#每日Linux小练习#11作业命令继续分析

在对比中发现不同 1.进程和作业的概念有所区别.一个正在执行的进程称为一个作业,而且作业可以包含一个或多个进程,尤其是当使用了管道和重定向命令.例如“nroff -man ps.1|grep kill|more”这个作业就同时启动了三个进程. 2.作业和bash是相关的,在进行工作管理的行为中,其实每个工作都是目前bash的子进程,即彼此之间具有相关性.比如无法使用job control的方式由tty1的环境去管理tty2的bash. 前台作业和后台作业 只有前台程序可以接受终端输入,后台作业试

#每日Linux小练习#09 trap指令

在有些情况下,我们不希望自己的shell脚本在运行时刻被中断,比如说我们写得shell脚本设为某一用户的默认shell,使这一用户进入系统后只能作某一项工作,如数据库备份, 我们可不希望用户使用ctrl+C之类便进入到shell状态,做我们不希望做的事情.这便用到了信号处理. trap命令用来指定shell需要捕捉哪些Linux信号,以及如何处理这些信号.格式如下: trap commands signals 不同的signal之间用空格隔开,commands表示如何处理signals. ech

#每日Linux小练习#06 Shell Script注意点总结

shell script优缺点分析 shell 使用的是外部的命令 与bash shell的一些默认工具,所以,它常常调用外部的函数库,因此,命令周期上面比不上传统的程序语言. 所以,Shell Script用在系统管理上面是很好的,但是在处理大量数值计算时,速度较慢. shell script编写的注意事项 1.如果一行内容太多,则可以使用 \[Enter] 来扩展至下一行 2.# 可以作为批注 如何执行Script 1.直接命令执行(要具有可读可执行的权限) 绝对路径,相对路径,变量PATH

小何讲进程: Linux进程的基本概念

1.  进程定义 进程是操作系统理论的核心与基础,操作系统中的许多概念都和进程相关. 进程的定义 ,进程有过各种各样的定义,现列举较为著名的几种. 进程是一个独立的可调度的活动: 进程是一个抽象实体,当它执行某个任务时,要分配和释放各种资源: 进程是可以并行执行的计算单位: 进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动: 进程是一个程序的一次执行过程,同时也是资源分配的最小单元. 进程和程序是有本质区别的: 程序是静态的,它是一些保存在磁盘上的指令的有序集合,没有任何执行的概念

每日linux命令学习-引用符号(反斜杠\,单引号'',双引号"")

引用符号在解析器中保护特殊元字符和参数扩展,其使用方法有3种:反斜杠(\),单引号(''),双引号(""). 单引号和双引号必须匹配使用,均可在解析器中保护特殊元字符和通配符,但是单引号(硬转义)主要用于信息的原样输出,防止任何变量的扩展,双引号(软转义)允许变量扩展.转义符和命令替换.单引号保护双引号,双引号保护单引号. 1. 反斜杠 反斜杠通过解析器将1个字符转化为引用符号或转义. 1)在单引号内使用反斜杠,反斜杠不会被解析,保持原样输出. 2)在双引号内使用反斜杠,主要用于美元符

我的常用linux小命令

这里并不是系统详细介绍每一个Linux命令,仅仅是记录本人在平时工作中经常用到的一些比较基础的命令及相关的参数,同时用了一些简单的例子来说明这些命令的用途,以及如何用多种命令来实现同一种功能. 1.ls命令 要显示当前目录下的文件列表时,我经常就使用ls命令的以下三个参数. -l 使用长列表格式 -h 文件大小以人可读的方式打印 -t 以最后修改时间排序,最新的放在最前 使用例子,如何显示当前文件夹下的目录? 方法1: ls -l | grep '^d' 方法2: ls -l | awk '/^

Centos 6.8 为自己打造Linux小系统

一.前言 Linux操作系统至1991.10.5号诞生以来,就源其开源性和自由性得到了很多技术大牛的青睐,每个Linux爱好者都为其贡献了自己的一份力,不管是在Linux内核还是开源软件等方面,都为我们后来人提供了一个良好的学习和研究环境.做为一个Linuxer,感谢各位前辈们为我们提供一个自由的空间,让我们也能够在学习的同时去研究Linux. 本文主要通过裁剪现有Linux系统,打造一个属于自己的Linux小系统,让其能够装载网卡驱动,并配置IP地址,实现网络功能. 二.原理 启动流程介绍:

Linux文件系统中的inode节点详细介绍

这篇文章主要介绍了Linux文件系统中的inode节点,详细讲解了inode是什么.inode包含的信息.inode号码的相关资料等. 一.inode是什么? 理解inode,要从文件储存说起.文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector).每个扇区储存512字节(相当于0.5KB). 操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个"块"(block).这种由多个扇区组成的"块&q

Linux内核OOM机制的详细分析(转)

Linux 内核 有个机制叫OOM killer(Out-Of-Memory killer),该机制会监控那些占用内存过大,尤其是瞬间很快消耗大量内存的进程,为了 防止内存耗尽而内核会把该进程杀掉.典型的情况是:某天一台机器突然ssh远程登录不了,但能ping通,说明不是网络的故障,原因是sshd进程被 OOM killer杀掉了(多次遇到这样的假死状况).重启机器后查看系统日志/var/log/messages会发现 Out of Memory: Kill process 1865(sshd)