【Linux】Linux进程管理

目录

一、程序与进程

1.程序如何变成进程

2.  Linux系统启动流程

3.进程状态

二、进程的产生

三、僵尸进程

什么是僵尸进程?

如何杀死僵尸进程

Linux进程趣图

四、进程的优先级和nice级别

进程与线程

进程和线程的关系如下所述:

进程和线程的区别如下所述:

 守护进程

五、Linux 进程间通信

​编辑

 信号 signal

常见的进程信号

Linux系统有7个运行级别(runlevel):

管道 pipe

 共享内存 shared memory

先入先出队列 FIFO

消息队列 Message Queue

套接字 Socket

六、系统启动的完整过程

七、查找命令的完整安装名称


一、程序与进程

程序(program)是一个普通文件,是为了完成特定任务而准备好的指令序列与数 据的集合,这些指令和数据以“可执行映像”的格式保存在磁盘中。例如:hello.c源程 序文件经过编译后产生a.out程序,其中a.out文件为可执行镜像格式,Linux 的/bin、/sbin、/usr/bin、/usr/sbin目录下保存着诸多的程序文件。

进程(process)是一个已经开始执行但还没终止的程序实例。Linux系统下使用ps 命令可以查看到当前正在执行的进程。每个进程包含有进程运行环境、内存地址空 间、进程ID、和至少一个被称为线程的执行控制流等资源。同一个程序可以实例化为 多个进程实体。操作系统中所有进程实体共享着计算机系统的CPU、外设等资源。

线程:操作系统进行运行调度的基本单位

也就是说进程是程序的动态执行,一旦运行就会有一个进程ID;

程序是一个静态的普通文件,里面包含为完成特定任务而准备的指令与数据,程序一旦运行结束就会将所占资源释放掉。

1.程序如何变成进程

程序是个静态的文件,进程是一个动态的实体,进程的状态会在运行过程中改变, 那么程序是如何变为一个进程的呢?

通常在Shell中输入命令运行就包含了程序到进程转换的过程。整个转换过程主要 包含以下3个步骤:

(1)查找命令对应程序文件的位置

(2)使用fork()函数创建一个新进程

(3)在新进程中调用exec族函数装载程序文件,并执行程序文件的main()函数

2.  Linux系统启动流程

1、硬件加电自建 BIOS

2、读取MBR信息 512bytes

3、 boot程序加载内核

4、内核初始化进程 init systemd runlevel 

5、建立终端: 虚拟终端

6、用户登录

     守护进程:在某些用户空间中,即使用户退出登录,仍然会有一些进程在后台运行

3.进程状态

Linux是一个多用户多任务的操作系统,可以同时运行多个用户的多个程序,就必 然会产生多进程,而每个进程会有不同的状态。Linux的进程有以下6种状态:

D = uninterruptible sleep D:不可中断的深度睡眠状态,处于这种状态的进程不能响应异步信号;不可中断 的等待状态最典型的例子就是进程等待磁盘I/O操作
R = running R:进程处于运行态或就绪状态,只有在该状态的进程才可能在CPU上运行。而同 一时刻可能有多个进程处于可执行状态;
S = sleeping S:可中断的睡眠状态,处于这个状态的进程因为等待某种事件的发生而被挂 起。;这类进程处于阻塞状态,一旦达到某种条件,就会变为运行状态。同时该状态 的进程也会由于接收到信号而被提前唤醒进入到运行状态。
T = stopped by job control signal

T:暂停状态或跟踪状态;进 向进程发送一个SIGSTOP信号,它就会因响应该信号而进入TASK_STOPPED状态(除非该进程本身处于ASK_UNINTERRUPTIBLE状态而不响应信号)

向进程发送一个SIGCONT信号,可以让其从TASK_STOPPED状态恢复到TASK_RUNNING状态。

X=TASK_DEAD - EXIT_DEAD X:退出状态,进程即将被销毁
Z = zombie Z:退出状态,进程成为僵尸进程

【Linux】Linux进程管理_第1张图片

【Linux】Linux进程管理_第2张图片

Linux系统使用ps -aux命令时可观察到进程的当前状态

【Linux】Linux进程管理_第3张图片

 当一个进程调用 fork 函数生成另一个进程,原进程就称为父进程新生成的进程 则称为子进程。 Linux 系统中这样父子进程非常多,我们可以使用 pstree 命令查看系统上的进程 「谱系」。

【Linux】Linux进程管理_第4张图片

二、进程的产生

        父进程(PPID)---复制自己的地址空间fork()创建一个新的子进程.

        子进程(PID)----每一个新进程会有一个PID

        所有的进程都可以创建子进程

        所有的进程的父进程是第一个系统进程的子进程。

三、僵尸进程

什么是僵尸进程?

前面提到过,在 Linux 环境中,我们是通过 fork 函数来创建子进程的。创建完毕 之后,父子进程独立运行,父进程无法预知子进程什么时候结束。

通常情况下,子进程退出后,它立即从内存中移除,但进程描述符仍然保留在内存中 (进程描述符占有极少的内存空间)。子进程的状态变成EXIT_ZOMBIE,并且向父 进程发送SIGCHLD(-17)信号,父进程会使用 wait 或 waitpid 函数进行回收子 进程的资源,并获得子进程的终止状态。在wait()调用之后,僵尸进程就完全从内存 中移除了。因此一个僵尸进程存在于其终止到父进程调用wait()函数。

但是,如果父进程先于子进程结束,则子进程成为孤儿进程。孤儿进程将被 init 进程 (进程号为1)领养,并由 init 进程对孤儿进程完成状态收集工作。

而如果子进程先于父进程退出,同时父进程太忙了,无瑕回收子进程的资源,子进程 残留资源(PCB)存放于内核中,变成僵尸(Zombie)进程,如下图所示:

【Linux】Linux进程管理_第5张图片

如果子进程在退出的时候父进程还处于等待状态,父进程还未苏醒,因此没人给子进程「收尸」,所以它就变成 了僵尸进程。

在CentOS7中PID的默认最大值为131072,PID的范围是0~4194304。如果僵尸进 程持续增加可能用占用大量PID,影响到新进程的创建。

如何杀死僵尸进程

对于普通进程,我们可以通过使用 kill 命令来杀死它们。 kill 命令它还有几个兄 弟,比如 pkill 和 killall ,虽然它们名称里都带 kill 这样杀气腾腾的字眼, 但它们实际上是被设计为向一个或多个进程发送信号。

在未指定的情况下,这几个命令默认发送的是 SIGTERM 信号。

普通进程可以被 kill ,但僵尸进程是不行的。为什么?因为僵尸进程本身就已经 「死」过一次了!如果还可以再「死」,那「僵尸」这个名号就没多大意义了。

僵尸进程其实已经就是退出的进程,因此无法再利用kill命令杀死僵尸进程。僵尸进 程的罪魁祸首是父进程没有回收它的资源,那我们可以想办法它其它进程去回收僵尸 进程的资源,这个进程就是 init 进程。

因此,我们可以直接杀死父进程,init 进程就会很善良地把那些僵尸进程领养过来, 并合理的回收它们的资源,那些僵尸进程就得到了妥善的处理了。


例如,如果 PID 5878 是一个僵尸进程,它的父进程是 PID 4809,那么要杀死僵尸 进程 (5878),您可以结束父进程 (4809):

kill -9 4809   #4809 is the parent, not the zombie

注意:杀死父进程时要非常小心,如果一个进程的父进程就是 PID 1 ,并且你还杀死 了它,那么系统将直接重启!这将是一个更可怕的故事!

Linux进程趣图

【Linux】Linux进程管理_第6张图片

 【Linux】Linux进程管理_第7张图片

四、进程的优先级和nice级别

Linux是一个多用户多任务的操作系统。所有的任务都放在一个队列中,操作系统根 据每个任务的优先级为每个任务分配合适的时间片(时间片是进程在处理器中执行时 间)。每个时间片很短,用户根本感觉不到是多个任务在运行,从而使所有任务共享 系统资源。因此,Linux可以在一个任务还未执行完时,短暂挂起此任务,去执行另 一个任务,过一段时间后再回来处理这个任务,直到这个任务完成才从任务队列中去 除。这就是单CPU操作系统多任务的概念

在单CPU的环境下,虽然系统可以运行多个任务,但是在某个时间点,CPU只能执行 一个进程(串行执行)。而在多CPU的环境下,某个时间点可以有多个进程同时执行 (并行执行)。这就是多核CPU比单核CPU处理性能高的原因

在CPU执行每个任务的过程中,进程优先级决定了进程在CPU中的执行顺序。优先级 越高的进程被处理器执行的的机会越大。

进程优先级由动态优先级和静态优先级决定,根据进程的行为,内核使用启发式算法 决定开启或关闭动态优先级。可以通过nice级别直接修改进程的静态优先级,拥有越 高的静态优先级的进程会获得更长的时间片。Linux支持的nice级别从19(最低优先 级)到-20(最高优先级),默认为0。只有root用户才能把进程的nice级别调整为 负数(让其具备较高优先级)。

【Linux】Linux进程管理_第8张图片

进程与线程

进程是程序的一次动态执行,它对应着从代码加载、执行至执行完毕的一个完整的过 程,是一个动态实体,它有自己的声明周期。进程因创建而产生,因调度而运行,因 等待资源或事件而被处于等待状态,因完成任务而被撤销。

线程是进程的一个实体,是CPU调度和分派的基本单位它是比进程更小的能独立运 行的基本单位一个线程可以创建和撤销另一个线程,同一个进程的多个线程之间可 以并发执行


进程和线程的关系如下所述:

  • 一个线程只能属于一个进程,而一个进程可以由多个线程
  • 线程是资源分配的最小单位,同一个进程的所有线程共享该进程的所有资源
  • 真正在处理器上运行的是线程

    进程和线程的区别如下所述:

  • 调度:线程作为调度和分配的基本单位,进程最为拥有资源的基本单位
  • 并发性:不仅进程可以并发执行,同一个进程的多个线程也可以并发执行
  • 拥有资源:进程是拥有资源的基本单位,线程不拥有系统资源,但可以访问隶属 于进程的资源
  • 系统开销:在创建和撤销进程时,由于系统都要为之分配和回收资源,导致系统 的开销明显大于创建或撤销线程时的开销

 守护进程

在某些用户空间中,即使用户退出登录,仍然会有一些后台进程在运行,这些进程被 称为 守护进程(daemon) 。(例如:httpd   atd)

systemctl status cornd          ##查看指定服务的状态

Linux 中有一种特殊的守护进程被称为 计划守护进程(Cron daemon) ,计划守护进程 可以每分钟醒来一次检查是否有工作要做,做完会继续回到睡眠状态等待下一次唤 醒。

Linux的大多数服务器就是用守护进程实现的。比如,Web服务器httpd等。同时, 守护进程完成许多系统任务。比如,作业规划进程crond, 打印进程lpd等。下面将 我理解的Linux下守护进程做一些解释和说明。同时将网上一个常用的解说Linux下守 护进程的程序作为实例介绍一下。

五、Linux 进程间通信

Linux 进程间的通信机制通常被称为 Internel-Process communication,IPC 下面 我们来说一说 Linux 进程间通信的机制,大致来说,Linux 进程间的通信机制可以分 为 6 种

【Linux】Linux进程管理_第9张图片

 信号 signal

信号是 UNIX 系统最先开始使用的进程间通信机制,因为 Linux 是继承于 UNIX 的, 所以 Linux 也支持信号机制,通过向一个或多个进程发送 异步事件信号 来实现,信号 可以从键盘或者访问不存在的位置等地方产生;信号通过 shell 将任务发送给子进 程。

你可以在 Linux 系统上输入 kill -l 来列出系统使用的信号,下面是我提供的一些 信号

【Linux】Linux进程管理_第10张图片

 进程可以选择忽略发送过来的信号,但是有两个是不能忽略的: SIGSTOP SIGKILL 信号

SIGSTOP 信号会通知当前正在运行的进程执行关闭操作,SIGKILL 信号会通知当前 进程应该被杀死除此之外,进程可以选择它想要处理的信号,进程也可以选择阻止 信号,如果不阻止,可以选择自行处理,也可以选择进行内核处理。如果选择交给内 核进行处理,那么就执行默认处理。

操作系统会中断目标程序的进程来向其发送信号、在任何非原子指令中,执行都可以 中断,如果进程已经注册了新号处理程序,那么就执行进程,如果没有注册,将采用 默认处理的方式。

例如:当进程收到 SIGFPE 浮点异常的信号后,默认操作是对其进行 dump(转储) 和 退出。信号没有优先级的说法。如果同时为某个进程产生了两个信号,则可以将它们 呈现给进程或者以任意的顺序进行处理。

常见的进程信号

【Linux】Linux进程管理_第11张图片

Linux系统有7个运行级别(runlevel):

  • 运行级别0:系统停机状态,系统默认运行级别不能设为0,否则不能正常启动
  • 运行级别1:单用户工作状态,root权限,用于系统维护,禁止远程登陆
  • 运行级别2:多用户状态(没有NFS)
  • 运行级别3:完全的多用户状态(有NFS),登陆后进入控制台命令行模式
  • 运行级别4:系统未使用,保留
  • 运行级别5:X11控制台,登陆后进入图形GUI模式
  • 运行级别6:系统正常关闭并重启,默认运行级别不能设为6,否则不能正常启动

忘记超级用户密码可以进入单用户工作状态去修改

  • init 0可以实现关机
  • init 6可以实现重启
  • init 3可以实现切换到文本界面
  • init 5可以实现切换到图形化界面

在图形化界面也可以通过快捷键CRTL+ALT+F3实现切换到文本界面,但是反过来不 行,因为文本界面不支持这种快捷键操作

管道 pipe

Linux 系统中的进程可以通过建立管道 pipe 进行通信 在两个进程之间,可以建立一个通道,一个进程向这个通道里写入字节流,另一个进 程从这个管道中读取字节流。管道是同步的,当进程尝试从空管道读取数据时,该进 程会被阻塞,直到有可用数据为止。shell 中的 管线 pipelines 就是用管道实现 的,当 shell 发现输出 

sort

它会创建两个进程,一个是 sort,一个是 head,sort,会在这两个应用程序之间建 立一个管道使得 sort 进程的标准输出作为 head 程序的标准输入。sort 进程产生的 输出就不用写到文件中了,如果管道满了系统会停止 sort 以等待 head 读出数据

【Linux】Linux进程管理_第12张图片

管道实际上就是 | ,两个应用程序不知道有管道的存在,一切都是由 shell 管理和控 制的。 

 共享内存 shared memory

两个进程之间还可以通过共享内存进行进程间通信,其中两个或者多个进程可以访问 公共内存空间。两个进程的共享工作是通过共享内存完成的,一个进程所作的修改可 以对另一个进程可见(很像线程间的通信)。【Linux】Linux进程管理_第13张图片

  •  在使用共享内存前,需要经过一系列的调用流程,流程如下
  • 创建共享内存段或者使用已创建的共享内存段 (shmget())
  • 将进程附加到已经创建的内存段中 (shmat())
  • 从已连接的共享内存段分离进程 (shmdt())
  • 对共享内存段执行控制操作 (shmctl())

先入先出队列 FIFO

先入先出队列 FIFO 通常被称为 命名管道(Named Pipes) ,命名管道的工作方式与常 规管道非常相似,但是确实有一些明显的区别。未命名的管道没有备份文件:操作系 统负责维护内存中的缓冲区,用来将字节从写入器传输到读取器。一旦写入或者输出 终止的话,缓冲区将被回收,传输的数据会丢失。相比之下,命名管道具有支持文件 和独特 API ,命名管道在文件系统中作为设备的专用文件存在。当所有的进程通信完 成后,命名管道将保留在文件系统中以备后用。命名管道具有严格的 FIFO 行为。

【Linux】Linux进程管理_第14张图片

 写入的第一个字节是读取的第一个字节,写入的第二个字节是读取的第二个字节,依 此类推。

消息队列 Message Queue

消息队列是用来描述内核寻址空间内的内部链接列表。可以按几种不同的方式将消息 按顺序发送到队列并从队列中检索消息。每个消息队列由 IPC 标识符唯一标识。消息 队列有两种模式,一种是 严格模式 , 严格模式就像是 FIFO 先入先出队列似的,消息 顺序发送,顺序读取。还有一种模式是 非严格模式 ,消息的顺序性不是非常重要。

套接字 Socket

还有一种管理两个进程间通信的是使用 socket ,socket 提供端到端的双相通信。 一个套接字可以与一个或多个进程关联。就像管道有命令管道和未命名管道一样,套 接字也有两种模式,套接字一般用于两个进程之间的网络通信,网络套接字需要来自 诸如 TCP(传输控制协议) 或较低级别 UDP(用户数据报协议) 等基础协议的支持。

套接字有以下几种分类

  • 顺序包套接字(Sequential Packet Socket) :此类套接字为最大长度固定的数 据报提供可靠的连接。此连接是双向的并且是顺序的。
  • 数据报套接字(Datagram Socket) :数据包套接字支持双向数据流。数据包套接 字接受消息的顺序与发送者可能不同。
  • 流式套接字(Stream Socket) :流套接字的工作方式类似于电话对话,提供双向 可靠的数据流。
  • 原始套接字(Raw Socket) :可以使用原始套接字访问基础通信协议。

六、系统启动的完整过程

七、查找命令的完整安装名称

如果直接yum一个命令有时候可能找不到,这时候使用下面的命令就可以查到他的安装包名称

yum search 命令

例如安装pstree命令,直接使用yum install -y pstree是无法安装的,要先使用yum search pstree来查找他的完整安装名称,再进行安装。 

【Linux】Linux进程管理_第15张图片

你可能感兴趣的:(Linux基础特性,linux,运维,服务器)