Linux 进程基本概念 什么是进程
操作系统(Operator System)概念操作系统,简称OS,是一个基本的程序集合,用来维护计算机基本的运行。操作系统主要由内核(进程管理、内存管理、文件管理、驱动管理)和其他程序(如函数库、shell等组成)。OS的目的是为了让计算机与硬件交互,管理所有的软硬件资源来为用户(应用程序)提供一个良好的执行环境。通俗的来讲就是一款“职业”的管理软件,如图:计算机管理硬件的方...
操作系统(Operator System)
概念
操作系统,简称OS,是一个基本的程序集合,用来维护计算机基本的运行。操作系统主要由内核(进程管理、内存管理、文件管理、驱动管理)和其他程序(如函数库、shell等组成)。OS的目的是为了让计算机与硬件交互,管理所有的软硬件资源来为用户(应用程序)提供一个良好的执行环境。通俗的来讲就是一款“职业”的管理软件,如图:
计算机管理硬件的方式:先将硬件用struct结构体描述起来,然后使用链表等高效的数据结构将他们组织起来。所以同理,操作系统管理进程的方式也是先将进程描述起来,再把进程组织起来!!
进程
什么是进程?
进程就是一个程序的执行实例,也就是正在执行的程序。在OS的眼里,进程就是一个担当分配系统资源(CPU时间、内存)的实体。
进程描述符-PCB
刚才我们提到OS管理硬件的方式是先描述、再组织。那么OS就是用一个进程控制块的数据结构(进程属性的集合)来描述进程信息的,也就是PCB(process control block),Linux操作系统下的PCB是 task_struct ,程序运行时它会被装载到RAM里来储存进程信息。
task_ struct内容
- 标示符: 描述本进程的唯一标示符,用来区别其他进程。
- 状态: 任务状态,退出代码,退出信号等。
- 优先级: 相对于其他进程的优先级。
- 程序计数器: 程序中即将被执行的下一条指令的地址。
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
- 上下文数据: 进程执行时处理器的寄存器中的数据。
- I/O状态信息: 包括显示的I/O请求,分配给进程的/O设备和被进程使用的文件列表。
- 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
- 其他信息
查看进程
ls /proc/进程PID
/proc 系统文件夹储存了进程的信息,我们可以通过 ls /proc 来查看,也可以用 ls /proc/进程PID 查看某个进程的进程信息
ps命令查找与进程相关的PID号:
ps a 显示现行终端机下的所有程序,包括其他用户的程序。
ps -A 显示所有程序。
ps c 列出程序时,显示每个程序真正的指令名称,而不包含路径,参数或常驻服务的标示。
ps -e 此参数的效果和指定"A"参数相同。
ps e 列出程序时,显示每个程序所使用的环境变量。
ps f 用ASCII字符显示树状结构,表达程序间的相互关系。
ps -H 显示树状结构,表示程序间的相互关系。
ps -N 显示所有的程序,除了执行ps指令终端机下的程序之外。
ps s 采用程序信号的格式显示程序状况。
ps S 列出程序时,包括已中断的子程序资料。
ps -t<终端机编号> 指定终端机编号,并列出属于该终端机的程序的状况。
ps u 以用户为主的格式来显示程序状况。
ps x 显示所有程序,不以终端机来区分
最常用的方法是ps aux,然后再通过管道使用grep命令过滤查找特定的进程,然后再对特定的进程进行操作。
ps aux | grep test | grep -v grep
查看名为 test 的进程
进程状态
kernel源码怎么说
/*
* 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) :只是⼀个返回状态,你不会在任务列表里看到这个状态。
- t(tracing stop追踪状态): ptrace拦截和修改系统调用
- Z(zombie):僵死状态
下面主要为大家介绍一下僵死状态:
僵尸进程 Z(zombie)
僵尸进程是处于僵死状态的进程(只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程便进入Z状态)
产生原因:子进程先于父进程退出,父进程(使用wait()系统调用)没有读取到子进程退出的返回代码,这时候子进程为了保存退出原因,因此进入僵死态不会释放所有资源。僵死进程会以终止状态保持在进程表中,并且会⼀直在等待父进程读取其退出状态代码。
危害:维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,假如⼀个父进程创建了很多子进程,但是不回收,就会造成内存资源的浪费,资源泄露。
下面为大家举一个例子:
#include <stdio.h>
#include <stdlib.h>
int main()
{
pid_t pid = fork();
if(pid < 0){
perror("fork");
return 1;
}
else if(pid > 0){ //parent
printf("parent[%d] is sleeping\n", getpid());
sleep(30);
}
else{
printf("chile[%d] is begin Z\n", getpid());
sleep(5);
exit(EXIT_SUCCESS);
}
return 0;
}
创建一个30秒的进程,子进程5秒后退出,子进程成为僵尸进程:
孤儿进程
相对于僵尸进程,那么必须提到的就是孤儿进程,同僵尸进程相反,假如父进程先于子进程退出,子进程便进入后台运行,成为孤儿进程,孤儿进程随后会被1号init进程领养并回收,也就是将其父进程变为init进程。
什么是1号init进程?
在Linux中有两种特殊的进程:
进程0:Linux引导中创建的第一个进程,完成加载系统后,演变为进程调度、交换及存储管理进程。
进程1:init 进程,由0进程创建,完成系统的初始化。是系统中所有其它用户进程的祖先进程。
如何创建0号进程?
由于在创建进程时,程序一直运行在内核态,而进程运行在用户态,因此创建0号进程涉及到特权级的变化,即从特权级0变到特权级3,Linux是通过模拟中断返回来实现特权级的变化以及创建0号进程,通过将0号进程的代码段选择子以及程序计数器EIP直接压入内核态堆栈,然后利用iret汇编指令中断返回跳转到0号进程运行。
代码如下:
move_to_user_mode(); //创建0号进程,开始进入0号进程,切换到特权级3运行
if (!fork()){
init();
}//创建1号进程
下面为大家演示一下孤儿进程:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid = fork();
if(pid < 0){
perror("fork");
exit(1);
}
else if(pid == 0){
printf("I am child, pid is %d\n", getpid());
sleep(10);
}
else{
printf("I am parent, pid is %d\n", getpid());
sleep(5);
exit(0);
}
return 0;
}
结果:
进程优先级
为什么要有进程优先级?
因为进程的功能各有不同因此对cpu资源的要求也各有不同,因此针对进程的调度就有了优先级,我们把cpu资源分配的先后顺序叫做进程的优先权,优先权决定了cpu资源的优先分配权,优先权高的进程有优先执行权利。还可以把不重要的进程安排到某个指定的cpu上,可以大大改善系统整体性能。
查看系统进程
ps -l
- UID:代表执行者的身份
- PID:代表进程代号
- PPID:代表进程是由哪个进程发展衍生而来的,亦即父进程的代号
- PRI:代表这个进程可悲执行的优先级,其值越小越早被执行
- NI:代表这个进程的nice值
PRI and NI
看看系统怎么说?
PRI:进程优先级(程序被CPU执行的先后顺序,越小进程优先级越高)
NI:nice值(进程可被执行的优先级修正数值)
取值范围-20至19,共40个级别
PRI(new) = PRI(old) + NI(nice)
意义:nice为负时,该程序优先级值会变小,优先级变高,越快被执行。所以调整进程优先级在Linux下也就是调整nice值
进程的nice值并不是进程的优先级,只是进程nice值会影响到进程的优先级变化,nice值是进程优先级的附加/修正数据
修改进程优先级:
#include <stdio.h>
int main()
{
printf("pid is %d\n", getpid());
while(1){
sleep(1);
}
return 0;
}
nice 和 renice 和 top
- nice:开始执行程序就指定nice值
- renice :调整已存在进程的nice
- top:更改已存在进程的nice
- 进⼊入top后按“r”–>输⼊入进程PID–>输⼊入nice值
进程其他概念:
- 竞争性:系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争 相关资源,便具有了优先级。
- 独立性:多进程运行,需要独享各种资源,多进程运行期间互不干扰
- 并行:多个进程在多个CPU下分别,同时进行,这称之为并行
- 并发:多个进程在⼀个CPU下采⽤用进程切换的方式,在⼀段时间之内,让多个进程都得以推进,称之为并发
环境变量
概念:在操作系统中用来指定操作系统运行环境的一些参数,如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态、静态库在哪里,但是照样可以链接成功,生成可执⾏行程序,原因就是有相关环境变量帮助编译器进行查找。
特征:环境变量在系统中通常具有全局特性
- echo:显示某个环境变量值
- env:显示所有环境变量
- set :显示本地定义的shell变量和环境变量
- unset:清除环境变量
- export:设置一个新的环境变量
环境变量的组织方式
如图:每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以'\0'结尾的环境字符串
通过代码如何获得环境变量
1.通过第三方变量environ获取(extern char **environ;)
libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件之中,所以在使用时需要extern声明
#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;
}
2.通过main函数第三个参数获取
#include <stdio.h>
int main(int argc, char *argv[], char *env[])
{
int i = 0;
for(; env[i]; i++){
printf("%s\n", env[i]);
}
return 0;
}
3.getenv("PATH") (或者putenv)
常用getenv和putenv函数来访问特定的环境变量。
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("%s\n", getenv("PATH"));
return 0;
}
环境变量通常具有全局属性,可以被子进程继承下去
#include <stdio.h>
#include <stdlib.h>
int main()
{
char * env = getenv("MYENV");
if(env){
printf("%s\n", env);
}
return 0;
}
运行后为什么没有任何结果?原因是环境变量MYENV根本不存在。
现在我们导出环境变量后再次运行:发现结果成功
下面再为大家演示一下删除环境变量
更多推荐
所有评论(0)