第四章:Linux进程概念与环境变量

系列文章目录



前言

进程是操作系统分配资源的最小单位,linux系统上的进程是如何表示和操作的呢?


一、冯诺依曼体系结构

大部分的计算机硬件体系都是冯诺依曼体系
在这里插入图片描述

  • 输入、输出设备:统称外设,有键盘、话筒、摄像头、网卡、磁盘等
  • 存储器:这里就是指内存
  • 中央处理器:运算器和控制器

1、内存的意义

所有设备都只能直接和内存打交道。
这样做的好处是将需要等待的数据存储到内存中,读取数据就是内存的速度,提升了计算机整体的运行速度。

2、数据流

即使是些简单操作,都用到每一部分。
QQ中传递文件:输入:磁盘、输出:网卡 、输入:网卡、输出:磁盘
QQ中聊天:输入:键盘、输出:网卡 、输入:网卡、输出:显示器

二、操作系统

任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。

操作系统包括:

  • 内核(进程管理,内存管理,文件管理,驱动管理)
  • 其他程序(例如函数库,shell程序等等)

1、操作系统的目的

  • 与硬件交互,管理所有的软硬件资源
  • 为用户程序(应用程序)提供一个良好的运行环境
    在这里插入图片描述
  1. 硬件部分遵守冯诺依曼体系

  2. OS不信任任何用户,任何对系统硬件或者软件访问,都必须通过OS的手

  3. 计算机体系是一个层状结构,任何访问硬件或者软件的行为,都必须通过OS接口,贯穿OS进行访问

  4. 库函数:语言或者第三方库(第一方:系统的、第二方:自己的,其余是第三方的)给我们提供的接口

  5. 系统调用:OS提供的接口

总结:

  • 计算机管理硬件:描述起来,用struct结构体组织起来,用链表或其他高效的数据结构
  • 操作系统是进行软硬件资源管理的软件(其中管理的本质是先描述在组织(是对数据的管理)
  • 管理分为三种:管理者、执行者、被管理者(eg管理者为OS、执行者为驱动程序、被管理者为底层硬件)

三、进程

1、基本概念

课本概念:程序的一个执行实例,正在执行的程序等
内核观点:担当分配系统资源(CPU时间,内存)的实体。
操作系统:内核关于进程的数据结构(PCB) + 当前进程的代码和数据
在这里插入图片描述

描述进程-PCB

  • 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。称之为PCB(process control block),Linux操作系统下的PCB是: task_struct 。task_struct是PCB的一种
  • 在Linux中描述进程的结构体叫做task_struct。
  • task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息

task_ struct内容分类

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

2、查看进程

ps axj
//查看进程
ps axj | head -1 && ps axj | grep "test"
//带标题栏和过滤带有“test"的进程
top
//查看进程占资源情况
ls /proc
ls /porc/xxx -al
//这些目录保存了当前系统中运行的所有进程的信息

3、通过系统调用创建进程-fork

在这里插入图片描述
1、创建子进程
在这里插入图片描述
在这里插入图片描述

  • fork有两个返回值的原因是在创建子进程成功之后,子进程和父进程共享代码
  • fork:子进程的返回值是0,父进程返回值是子进程的pid,因为子进程只有一个父进程,而父进程有多个子进程,需要对每个子进程进行标识(pid),并且记住他们
  • 父子进程代码共享,数据各自开辟空间,私有一份(采用写时拷贝)

四、进程状态

1、linux内核源码

/*
* 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): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠
  • D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
  • T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
  • X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。
  • Z(zombie)-僵尸进程:

在这里插入图片描述

2、僵尸进程

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

在这里插入图片描述

3、孤儿进程

父进程先退出,子进程就称之为“孤儿进程”

五、进程优先级

进程的优先级:

  • cpu资源分配的先后顺序,就是指进程的优先权(priority)。
  • 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
  • 还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能
  • 优先级是在一定能得到某种资源,只是先后的问题
  • 权限是决定你能还是不能得到某种资源
  • 优先级是得到某种资源(CPU)的先后顺序,其本质是因为资源有限(CPU

1、查看进程优先级

在这里插入图片描述

  • UID : 代表执行者的身份
  • PID : 代表这个进程的代号
  • PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
  • PRI :代表这个进程可被执行的优先级,其值越小越早被执行
  • NI :代表这个进程的nice值
  1. Linux的优先级由pri和nice值共同确定(优先级的数值越小,优先级越高;优先级的数值越大,优先级越低)
  2. nice值就是优先级的修正数据,范围是[-20,19]
  3. 优先级不可能一味的高,也不可能一味的低(操作系统的调度器要适度地考虑平衡问题,避免“饥饿问题”)

2、设置进程优先级

  • PRI是进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小
    进程的优先级别越高
  • NI就是nice值了,其表示进程可被执行的优先级的修正数值
  • PRI值越小越快被执行,PRI(new)=PRI(old)+nice
  • 当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行
  • 调整进程优先级,在Linux下,就是调整进程nice值
  • nice其取值范围是-20至19,一共40个级别。
  • 进程的nice值不是进程的优先级,但是进程nice值会影响到进程的优先级变化。
  • nice值是进程优先级的修正修正数据
    在这里插入图片描述
  • 竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级
  • 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰
  • 并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行
  • 并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发

六、环境变量与命令行参数

1、基本概念

环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数。如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性

  • PATH : 指定命令的搜索路径
  • HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
  • SHELL : 当前Shell,它的值通常是/bin/bash。
  • 查看环境变量方法:echo $NAME //NAME:你的环境变量名称

2、查看环境变量

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

3、环境变量通常是具有全局属性的

命令行中一般有两个变量:本地变量、环境变量
本地变量:只能够在当前shell命令行解释器内被访问,不可以被子进程继承
环境变量:具有”全局属性“ 可以被子进程继承

  • echo: 显示某个环境变量值
  • export: 设置一个新的环境变量
  • env: 显示所有环境变量
  • unset: 清除环境变量
  • set: 显示本地定义的shell变量和环境变量

4、命令行参数

在这里插入图片描述

  • 命令行参数可以帮助我们设计出,在同一个程序中可以设计出不同的业务功能
  • argv指针数组,其中最后一个元素指向的是NULL

5、环境变量的组织方式及通过代码如何获取环境变量

每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串

在这里插入图片描述
此外还可以用这种方式

#include <stdio.h>
int main(int argc, char *argv[])
{
    
    
 extern char **environ;
 int i = 0;
 for(; environ[i]; i++){
    
    
 printf("%s\n", environ[i]);
 }
 return 0;
}

七、进程地址空间

1、进程地址空间的分布

在这里插入图片描述

  • 进程地址空间不是内存地址空间
  • 进程地址空间,会在进程的整个生命周期内一直存在,直到进程退出

2、什么是进程地址空间

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 0;
int main()
{
    
    
	pid_t id = fork();
 	if(id < 0)
 	{
    
    
		perror("fork");
 		return 0;
 	}
 	else if(id == 0)
 	{
    
     
 		//child,子进程肯定先跑完,也就是子进程先修改,完成之后,父进程再读取
 		g_val=100;
 		printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
 	}
 	else
 	{
    
     
 		//parent
 		sleep(3);
		printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
 	}
 	sleep(1);
 	return 0;
}
child[3046]: 100 : 0x80497e8
parent[3045]: 0 : 0x80497e8

父子进程中的g_val的地址竟然是一样的

  • 任何的编程语言里面的地址,绝对不是物理地址,而是虚拟地址(C++/C语言中的&得到的是虚拟地址不是物理地址)
  • 虚拟地址是操作系统提供的,数据和代码一定在物理内存上(冯诺依曼规定),因此需要将虚拟内存转化成物理内存(由OS自动完成)
  • 父子进程代码共享,而数据是各自私有一份的(写时拷贝)
  • 当所有程序运行起来之后,该程序立即变成进程

地址空间本质是进程看待内存的方式,是抽象出来的一个概念,内核struct mm_struct,这样的每一个进程,都认为自己独占系统内存资源
区域划分本质:将线性地址空间划分成为一个一个的area,[start,end]
虚拟地址本质:在[start,end] 之间的各个地址叫做虚拟地址
在这里插入图片描述

在这里插入图片描述


总结

进程管理是操作系统的重要作用之一。
强烈的信仰会赢取坚强的人,然后又使他们更坚强。——华特贝基霍

猜你喜欢

转载自blog.csdn.net/yanyongfu523/article/details/129808252