-
基本概念
-
课本概念: 程序的一个执行实例,正在执行的程序等。
-
内核观点: 担当分配系统资源(CPU时间,内存)的实体。
-
-
描述进程-PCB
-
进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合
-
task_struct-PCB的一种
-
PCB实际上是对进程控制块的统称,在Linux中描述进程的结构体叫做task_struct。
-
task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含进程的信息。
-
-
task_struct内容分类
-
标示符: 描述本进程的唯一标示符,用来区别其他进程。
-
状态: 任务状态,退出代码,退出信号等。
-
优先级: 相对于其他进程的优先级。
-
程序计数器(pc): 程序中即将被执行的下一条指令的地址。
-
内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。
-
上下文数据: 进程执行时处理器的寄存器中的数据。
-
I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
-
记账信息: 可能包括处理器时间总和,使用的时钟总和,时间限制,记账号等。
-
其他信息。
-
-
-
操作系统将每一个进程都进行描述,形成了一个个的进程控制块(PCB),并将这些PCB以双链表的形式组织起来。
-
-
查看进程
-
通过系统目录查看
-
根目录下有一个名为proc的系统文件夹。
-
有些子目录的目录名为数字。数字其实是某一进程的PID,对应文件夹当中记录着对应进程的各种信息
-
例: ls /proc/1
-
-
通过ps命令查看
-
单独使用ps命令,会显示所有进程信息。
-
ps aux
-
-
ps命令与grep命令搭配使用,即可只显示某一进程的信息。
-
ps aux | head -1 && ps aux | grep proc | grep -v grep
-
-
-
-
通过系统调用获取进程的PID和PPID
-
通过使用系统调用函数,getpid和getppid即可分别获取进程的PID和PPID。
-
-
通过系统调用创建进程-fork初识
-
fork函数创建子进程
-
在fork函数被调用之前的代码被父进程执行,而fork函数之后的代码,则默认情况下父子进程都可以执行。
-
需要注意的是,父子进程虽然代码共享,但是父子进程的数据各自开辟空间(采用写时拷贝)
-
-
使用if分流
-
fork函数的返回值:
-
1、如果子进程创建成功,在父进程中返回子进程的PID,而在子进程中返回0。
-
2、如果子进程创建失败,则在父进程中返回 -1。
-
-
可以根据fork的返回值进行if分流,达到让父子进程各自完成对应任务的目的
-
-
-
-
Linux进程状态
-
运行状态-R
-
task_struct处于运行队列中(排队中)/或者正在进行
-
运行先后由操作系统调度
-
-
-
-
阻塞状态
-
等待非CPU资源就绪
-
-
挂起状态
-
内存快不足的时候,操作系统会将长时间不执行的进程代码和数据换出到磁盘
-
此时进程的状态就叫挂起
-
-
浅度睡眠状态-S
-
可中断睡眠
-
演示代码
#include<stdio.h> #include <unistd.h> int main() { printf("正在运行......\n"); sleep(50); return 0; }
运行结果
-
ps aux | head -1 && ps aux | grep test | grep -v grep
-
-
深度睡眠状态-D
-
不可以被中断
-
不可以被唤醒
-
磁盘睡眠
-
-
暂停状态-T
-
应用场景:调试,对进程发送暂停信号
-
kill -SIGSTOP 18209
代码
-
#include<stdio.h> #include <unistd.h> int main() { while(1) { printf("hello\n"); } return 0; }
演示结果 -
-
-
僵尸状态-Z
-
是什么
-
一个进程已经退出,但是害不允许被os释放,处于一个被检测的状态
-
一般是父进程或者操作系统检测
-
-
为什么
-
维持这个状态,方便父进程或者OS回收
-
-
-
死亡状态-X
-
终止状态
-
-
-
僵尸进程
-
僵尸进程的危害
-
僵尸进程的退出状态必须一直维持下去,因为它要告诉其父进程相应的退出信息。可是父进程一直不读取,那么子进程也就一直处于僵尸状态。
-
僵尸进程的退出信息被保存在task_struct(PCB)中,僵尸状态一直不退出,那么PCB就一直需要进行维护。
-
若是一个父进程创建了很多子进程,但都不进行回收,那么就会造成资源浪费,因为数据结构对象本身就要占用内存。
-
僵尸进程申请的资源无法进行回收,那么僵尸进程越多,实际可用的资源就越少,也就是说,僵尸进程会导致内存泄漏。
-
-
孤儿进程
-
子进程在父进程之前退出
-
由1号init进程领养,也由他回收
-
代码演示
-
-
-
演示结果
-
-
进程优先级
-
基本概念
-
为什么有优先级
-
cpu是有限的,进程太多,需要通过某种方式竞争资源
-
-
什么是优先级
-
确定是谁应该先获得某种资源,谁后获得
-
通过一些数据表明优先级
-
-
老的优先级+nice值
-
-
-
查看系统进程
-
UID:代表执行者的身份。
-
PID:代表这个进程的代号。
-
PPID:代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号。
-
PRI:代表这个进程可被执行的优先级,其值越小越早被执行。
-
NI:代表这个进程的nice值。
-
-
PRI与NI
-
PRI代表进程的优先级(priority),通俗点说就是进程被CPU执行的先后顺序,该值越小进程的优先级别越高。
-
NI代表的是nice值,其表示进程可被执行的优先级的修正数值。
-
PRI值越小越快被执行,当加入nice值后,将会使得PRI变为:PRI(new) = PRI(old) + NI。
-
若NI值为负值,那么该进程的PRI将变小,即其优先级会变高。
-
调整进程优先级,在Linux下,就是调整进程的nice值。
-
NI的取值范围是-20至19,一共40个级别。
-
注意: 在Linux操作系统当中,PRI(old)默认为80,即PRI = 80 + NI。
-
-
查看进程优先级信息
-
ps -al
-
-
通过top命令更改进程的nice值
-
通过renice命令更改进程的nice值
-
四个重要概念
-
竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便有了优先级。
-
独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。
-
并行: 多个进程在多个CPU下分别同时进行运行,这称之为并行。
-
并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。
-
-
-
环境变量
-
基本概念
-
一般是指在操作系统中用来指定操作系统运行环境的而一些参数
-
-
常见环境变量
-
PATH
-
指定命令的搜索路径
-
-
HOME
-
指定用户的祝工作目录
-
-
SHELL
-
当前shell,一般是/bin/bash
-
-
-
查看环境变量的方法
-
env--查看所有环境变量
-
-
-
-
-
echo $NAME
-
-
测试PATH
-
echo $PATH
-
-
而系统就是通过环境变量PATH来找到ls命令
-
set PATH=$PATH:当前路径
-
-
那可不可以让我们自己的可执行程序也不用带路径就可以执行呢?
-
方式一:将可执行程序拷贝到环境变量PATH的某一路径下。
-
方式二:将可执行程序所在的目录导入到环境变量PATH当中
-
-
测试HOME
-
echo $HOME
-
-
-
测试SHELL
-
echo $SHELL
-
-
-
-
和环境变量相关的命令
-
echo
-
显示某个环境变量值
-
-
export
-
设置一个新的环境变量
-
-
env
-
显示所有环境变量
-
-
unset
-
清楚环境变量
-
-
set
-
显示本地定义的shell变量和环境变量
-
-
-
环境变量的组织方式
-
-
通过代码获取环境变量
-
main的第三个变量
-
-
main函数的第三个参数接收的实际上就是环境变量表,我们可以通过main函数的第三个参数来获取系统的环境变量。
#include<stdio.h>
#include <unistd.h>
int main(int argc,char *argv[],char* envp[])
{
//方式一
int i=0;
while(envp[i])
{
printf("envp[i]: %S\n",envp[i]);
i++;
}
//方式二
// //或者用一个变量来接收
// extern char** environ;
// int i=0;
// while(environ[i])
// {
// printf("%s\n",environ[i]);
// }
return 0;
}
-
-
演示效果
-
通过系统调用获取环境变量
-
-
通过代码获取到环境变量还需要对返回的字符串做接收,才能继续做后面的操作。实际上操作系统自己就有系统调用接口来获取环境变量
-
setenv函数--设置环境变量
-
getenv函数--获得环境变量
-
代码演示
-
-
#include<stdio.h>
#include<stdlib.h>
int main()
{
printf("HOME: %s\n",getenv("HOME"));
return 0;
}
-
-
-
演示效果
-
-
-
程序地址空间
-
代码演示
#include<stdlib.h>
#include<stdio.h>
int g_val=10;
int g_uval;
int main(int argc,char* argv[],char* envp[])
{
printf("代码区:%p\n",main);
char* str="abcde";
printf("只读常量区: %p\n",str);
printf("初始化数据区: %p\n",&g_val);
printf("未初始化数据区: %p\n",&g_uval);
int *p=(int*)malloc(10);
printf("堆区: %p\n",p);
printf("栈区: %p\n",&p);
printf("###############\n");
int i=0;
for(i=0;i<argc;i++)
{
printf("命令行参数:%p\n",argv[i]);
}
while(envp[i])
{
printf("环境变量: %p\n",&envp[i]);
i++;
}
return 0;
}
-
演示效果
-
进程地址空间
-
较为详细的xmind可以通过以下链接下载