【Linux】进程

----------------| 本文目录 |----------------

  • [1. 进程](#1. 进程)
    • [1.1 基本概念](#1.1 基本概念)
    • [1.2 描述进程 - PCB](#1.2 描述进程 - PCB)
      • [1.2.1 task_struct - PCB的一种](#1.2.1 task_struct - PCB的一种)
      • [1.2.2 task_struct 内容分类](#1.2.2 task_struct 内容分类)
    • [1.3 组织进程](#1.3 组织进程)
    • [1.4 查看进程](#1.4 查看进程)
    • [1.5 通过系统调用获取进程标示符](#1.5 通过系统调用获取进程标示符)
    • [1.6 通过系统调用创建进程 - fork初识](#1.6 通过系统调用创建进程 - fork初识)
  • [2. 进程状态](#2. 进程状态)
    • [2.1 看看Linux内核源代码怎么说](#2.1 看看Linux内核源代码怎么说)
    • [2.2 进程状态查看](#2.2 进程状态查看)
    • [2.3 Z(zombie) - 僵尸进程](#2.3 Z(zombie) - 僵尸进程)
    • [2.4 僵尸进程危害](#2.4 僵尸进程危害)
    • [2.5 进程状态总结](#2.5 进程状态总结)
    • [2.6 孤儿进程](#2.6 孤儿进程)
  • [3. 进程优先级](#3. 进程优先级)
    • [3.1 基本概念](#3.1 基本概念)
    • [3.2 查看系统进程](#3.2 查看系统进程)
      • [3.2.1 PRI and NI](#3.2.1 PRI and NI)
      • [3.2.2 PRI vs NI](#3.2.2 PRI vs NI)
    • [3.3 查看进程优先级的命令](#3.3 查看进程优先级的命令)
      • [3.3.1 用 top 命令更改已存在进程的 nice](#3.3.1 用 top 命令更改已存在进程的 nice)
    • [3.4 其他概念](#3.4 其他概念)

1. 进程

1.1 基本概念

  • 课本概念:程序的一个执行实例,正在执行的程序等。
  • 内核观点:担当分配系统资源(CPU时间,内存)的实体。

1.2 描述进程 - PCB

  • 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。
  • 课本上称之为 PCB(process control block),Linux 操作系统下的 PCB 是:task_struct

1.2.1 task_struct - PCB的一种

  • 在 Linux 中描述进程的结构体叫做 task_struct。
  • task_struct 是 Linux 内核的一种数据结构,它会被装载到 RAM(内存)里并且包含着进程的信息。

1.2.2 task_struct 内容分类

  • 标示符:描述本进程的唯一标示符,用来区别其他进程。
  • 状态:任务状态,退出代码,退出信号等。
  • 优先级:相对于其他进程的优先级。
  • 程序计数器:程序中即将被执行的下一条指令的地址。
  • 内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。
  • 上下文数据:进程执行时处理器的寄存器中的数据。
  • I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
  • 记账信息:可能包括处理器时间总和,使用的时钟数总和,时间限制,记帐号等。
  • 其他信息...

1.3 组织进程

可以在内核源代码里找到它。所有运行在系统里的进程都以 task_struct 链表的形式存在内核里。

1.4 查看进程

进程的信息可以通过 /proc 系统文件夹查看。

  • 如:要获取 PID 为 1 的进程信息,你需要查看 /proc/1 这个文件夹。
  • 大多数进程信息同样可以使用 top 和 ps 这些用户级工具来获取。
c 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
	while (1)
	{
		sleep(1);
	}
	return 0;
}

1.5 通过系统调用获取进程标示符

  • 进程 id(PID)
  • 父进程 id(PPID)
c 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    printf("pid: %d\n", getpid());
    printf("ppid: %d\n", getppid());
    return 0;
}

1.6 通过系统调用创建进程 - fork初识

  • 运行 man fork 认识 fork
  • fork 有两个返回值
  • 父子进程代码共享,数据各自开辟空间,私有一份(采用写时拷贝)
c 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    int ret = fork();
    printf("hello proc: %d!, ret: %d\n", getpid(), ret);
    sleep(1);
    return 0;
}
  • fork 之后通常要用 if 进行分流
c 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    int ret = fork();
    if (ret < 0)
    {
        perror("fork");
        return 1;
    }
    else if (ret == 0)
    {
        // child                                                                       
        printf("I am child: %d!, ret: %d\n", getpid(), ret);
    }
    else
    {
        // father
        printf("I am father: %d!, ret: %d\n", getpid(), ret);
    }
    sleep(1);
    return 0;
}

2. 进程状态

2.1 看看Linux内核源代码怎么说

为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在Linux内核里,进程有时候也叫任务)。

下面是状态在 kernel 源代码里定义:

c 复制代码
/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};
  • R运行状态(running):并不意味着进程一定在运行中,它表明进程要么是在运行中,要么在运行队列里。
  • S睡眠状态(sleeping):意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。
  • D磁盘休眠状态(Disk sleep):有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
  • T停止状态(stopped):可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
  • X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。

2.2 进程状态查看

powershell 复制代码
ps aux / ps axj 命令

2.3 Z(zombie) - 僵尸进程

  • 僵尸状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用)没有读取到子进程退出的返回代码时,就会产生僵尸进程。
  • 僵尸进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。
  • 所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入 Z 状态。

创建一个维持30秒的僵尸进程例子:

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    pid_t id = fork();
    if (id < 0)
    {
        perror("fork");
        return 1;
    }
    else if (id > 0)
    {
        // parent
        printf("parent[%d] is sleeping...\n", getpid());
        sleep(30);                                                      
    }
    else
    {
        // child
        printf("child[%d] is begin Z...\n", getpid());
        sleep(5);
        exit(EXIT_SUCCESS);
    }
    return 0;
}

编译并在另一个终端下启动监控

开始测试

看到结果

2.4 僵尸进程危害

  • 进程的退出状态必须被维持下去,因为他要告诉关心他的进程(父进程):你交给我的任务,我办的怎么样了。可父进程如果一直不读取,那子进程就一直处于
    Z 状态?是的!
  • 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在 task_struct(PCB)中,换句话说,Z 状态一直不退出,PCB 一直都要维护?是的!
  • 那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本身就要占用内存,想想 C 中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间!
  • 内存泄漏?是的!

2.5 进程状态总结

  • 至此,值得关注的进程状态全部讲解完成,下面来认识另一种进程。

2.6 孤儿进程

  • 如果父进程提前退出,子进程后退出,进入 Z 状态后,该如何处理呢?
  • 父进程先退出,子进程就称之为"孤儿进程"。
  • 孤儿进程被 1 号 init 进程领养,当然要由 init 进程回收。
c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    pid_t id = fork();
    if (id < 0)
    {
        perror("fork");
        return 1;
    }  
    else if (id == 0)
    {  
        // child
        printf("I am child, pid: %d\n", getpid());
        sleep(10);                                             
    }
    else
    {  
        // parent
        printf("I am parent, pid: %d\n", getpid());
        sleep(3);
        exit(0);
    }
    return 0;
}

3. 进程优先级

3.1 基本概念

  • CPU 资源分配的先后顺序,就是指进程的优先权(priority)。
  • 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的 Linux 很有用,可以改善系统性能。
  • 还可以把进程运行到指定的 CPU 上,这样一来,把不重要的进程安排到某个 CPU,可以大大改善系统整体性能。

3.2 查看系统进程

在 Linux 或者 Unix 系统中,用 ps -l 命令则会类似输出以下几个内容:

我们很容易注意到其中的几个重要信息,如下:

  • UID:代表执行者的身份
  • PID:代表这个进程的代号
  • PPID:代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
  • PRI:代表这个进程可被执行的优先级,其值越小越早被执行
  • NI:代表这个进程的 nice 值

3.2.1 PRI and NI

  • PRI 也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被 CPU 执行的先后顺序,此值越小进程的优先级别越高。
  • 那 NI 呢?就是我们所要说的 nice 值了,其表示进程可被执行的优先级的修正数值。
  • PRI 值越小越快被执行,那么加入 nice 值后,将会使得 PRI 变为:PRI(new) = PRI(old) + nice。
  • 这样,当 nice 值为负的时候,该程序会将优先级值变小,即:其优先级会变高,会更快的被执行。
  • 所以,调整进程优先级,在 Linux 下,就是调整进程 nice 值。
  • nice 其取值范围为: -20 ~ 19,一共 40 个级别。

3.2.2 PRI vs NI

  • 需要强调的一点是:进程的 nice 值不是进程的优先级,他们不是一个概念,但是进程 nice 值会影响到进程的优先级变化。
  • 可以理解 nice 值是进程优先级的修正数据。

3.3 查看进程优先级的命令

3.3.1 用 top 命令更改已存在进程的 nice

  1. 使用 top 命令
  1. 进入 top 后按 "r"
  1. 输入进程 PID
  1. 输入 nice 值

3.4 其他概念

  • 竞争性:系统进程数目众多,而 CPU 资源只有少量,甚至 1 个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。
  • 独立性:多进程运行,需要独享各种资源,多进程运行期间互不干扰。
  • 并行:多个进程在多个 CPU 下分别、同时进行运行,这称之为并行。
  • 并发:多个进程在一个 CPU 下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。

END

相关推荐
脱了格子衬衫39 分钟前
linux安装ansible
linux·运维·ansible
小丑西瓜6661 小时前
MySQL库操作
linux·服务器·数据库·mysql
小珑也要变强3 小时前
shell脚本基本概念讲解
linux·运维
爱吃喵的鲤鱼4 小时前
linux 用C语言编写自己的myshell
linux·运维·服务器·c语言·算法
矛取矛求8 小时前
Linux如何更优质调节系统性能
linux
内核程序员kevin9 小时前
在Linux环境下使用Docker打包和发布.NET程序并配合MySQL部署
linux·mysql·docker·.net
kayotin9 小时前
Wordpress博客配置2024
linux·mysql·docker
Ztiddler10 小时前
【Linux Shell命令-不定期更新】
linux·运维·服务器·ssh
小小不董10 小时前
Oracle OCP认证考试考点详解082系列16
linux·运维·服务器·数据库·oracle·dba
a1denzzz10 小时前
Linux系统的网络设置
linux·服务器·网络