linux 系统
- 一.进程状态:
- 1.睡眠状态(sleep):
- 2.磁盘休眠状态(disk sleep):
- 3.停止状态(stoped --- T):
- 4.死亡状态:
- 5.控制状态(t)
- 二.僵尸进程和孤儿进程:
- 1.僵尸状态:
- 2.孤儿进程:
- 三.进程优先级:
- 1.基本概念:
- 2.系统进程的详细信息!
- 3.PRI 和 NI
- 四:linux 进程调度与切换
- 1.其他概念:
- 2.进程切换:
- 3.进程调度:
- 五.环境变量:
- 1.mian函数参数(实现命令行的基础):
- 2.bash 获取命令行字符串是如何进行传参?
- 3.环境变量:
- 1.常见环境变量:
- 2.如何把自己的程序变成不需要./就可以执行:
- 3.环境变量相关命令:
- 4.代码获取环境变量:
- 5.获取单个环境变量:
- 6.通过环境变量对程序进行加密:
- 7:本地变量和环境变量的区别!
- 4.环境变量一开始是从哪里获取到的?
一.进程状态:
/*
* 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 */
};
1.睡眠状态(sleep):
1.表示进程正在等待事件完成!
2对于一个进程我们在运行代码的时候大多数的情况都是一个睡眠状态。
3.运行状态占这个代码运行比较少的一部分时间!
4.下面是我们用来测试睡眠状态的代码!
2.磁盘休眠状态(disk sleep):
1.这是一个非常重要的状态这个状态是需要一个前提的!
2.说一个故事:在外面的内存中有一个进程正在跑这个进程主要干把一个数据写入磁盘的命令给到磁盘,磁盘就开始写数据到对应的位置,磁盘一直在写数据,然后这个时候内存中的进程就比较轻松在等待磁盘写入是否成功(条件一)的一个信息,操作系统的内存吃紧(条件二:)操作系统就会开始进行换入换出操作,当换入和换出比较更加紧张的时候就会进行进程的删除。
3.产生一个情况:磁盘进行数据写入完成没有成功,返回一个信息要给到进程,磁盘探了探头找进程,磁盘没有找到进程怎么办?当前磁盘也是非常的忙因为操作系统也一直在找磁盘进行换入换出,那么这个没有完成资源写入的操作的信息就被丢弃了!
4.有了上面的前提就知道了在 diak sleep 状态进程通常会等待IO结束!,这个状态也叫做不可中断睡眠!
5.最后呢这个状态是制作不了动图给大家看是因为如果我写一个数据需要disk sleep 我的操作系统离死也不远了!
3.停止状态(stoped — T):
1.进程停止状态就是一个直接停止一下之后什么也不去做了!
2.我们需要通过发送命令的方法进行进程停止的管理:
3.命令可以通过命令:kill -l 命令进行查询!
4. 19 (SIGSTOP)停止!
5. 18 (SIGCONT)进程开启!
6. 进程会进行前后台的切换,对应到状态就是字符后面有没有+ 号 , 有+号就是前台进程,没有+ 号就是后台进程!
7.前台进程可以通过 ctrl+c 结束程序!后台程序只能通过 kill -9 进程号 去删除进程!
4.死亡状态:
1.死亡状态是一个瞬时状态!这个时间非常非常短,学习过高中物理的同学应该知道有一个瞬时速度的概念跟这里的死亡的瞬时状态非常相似!
5.控制状态(t)
1.这个是我们在进行调试的时候的一个状态!
2.生成的可调试的degug程序进行调试可以观察到这个状态!
二.僵尸进程和孤儿进程:
1.僵尸状态:
1.下面这个代码的意思就是父进程产生一个子进程,分开进行运行然后子进程完成并且退出。
2.代码和数据被释放了,但是PCB task_struct 没有被释放里面保存着我们需要返回的值。
3.我们需要父进程把这个子进程PCB中的数据拿出来,我们的父进程一直没有去拿这个数据,task_struct 中的内容一直没有被释放在内存中!
4.产生内存泄漏,在系统中对于进程不进行task_struct 对象的释放也会产生内存泄漏!
5.数据读取完成之后task_struct Z -> X
6.所有的进程在结束之前都会产生一个情况就是 Z --> X 状态非常的快!
7.bash 会去自动读取父进程的返回状态!
int main()
{pid_t fither = getpid();pid_t tmp = fork();if(tmp == 0){int cat = 5;while(cat!=0){printf("I am child process pid:%d ppid:%d\n",getpid(),getpid());sleep(1);cat--;}exit(0);}else if(tmp>0){while(1){printf("I am fither process pid:%d ppid:%d\n",getpid(),getppid());sleep(1);}}return 0;
}
2.孤儿进程:
1.如果父进程先进行退出,然后子进程后退出。
2.如果父进程先退出,子进程就被称为“给 孤儿进程”
3.孤儿进程会被 1 号进程init进行领养,并且被1 号进程进行回收!
int main()
{pid_t fither = getpid();pid_t tmp = fork();if(tmp == 0){while(1){printf("I am child process pid:%d ppid:%d\n",getpid(),getpid());sleep(1);}}else if(tmp>0){int cat = 5;while(cat!=0){printf("I am fither process pid:%d ppid:%d\n",getpid(),getppid());sleep(1);cat--;}exit(0);}return 0;
}
三.进程优先级:
1.基本概念:
1.cpu 资源分配的先后顺序,就是指进程的优先级。
2.前提:进程访问某个资源,进程通过一定的方式进行排队确认享受资源的先后顺序!(因为资源比较少)
3.优先权高的有优先执行权限对多任务的linux 环境是非常有好处的!
4.为什么需要优先级(进程排队的方式),举一个例子如果学校的食堂的窗口比学校的所有人都要多基本上是不需要进行排队的!(需要排队:资源紧张!)
2.系统进程的详细信息!
1.命令:ps -l
2.ps -l 查询一些关于进程的信息:
3.PRI 和 NI
1.PRI 是优先级的值,值越小优先级越高。
2.PRI 是在[60 , 99]的这个范围里面。
2.PRI系统默认的大小是80:
4.NI 又叫nice(取值范围:[-20 , 19])值 , 是linux系统下用来调整优先级的工具我们不能直接调整PRI 的值是通过给nice值操作系统来进行数值意义的合并.
5.PID = 老的PID + nice 值 这个计算是操作系统在内核中完成的!并且这个操作是通过nice 值和 PID的值在一起进行统一管理优先级!
6.使用top 命令修改进程的nice值:进入top 后按 r 输入进程pid :输入nice值!
7.总结:进程的优先级不需要自己去手动更改这会影响操作系统的稳定性:这个东西是没有修改的必要的操作系统都给你做好了!
为什么设置优先级约束?
1.如果没有优先级的约束,程序员把自己的程序的优先级调整的非常高,别人的优先级就会比较低。
2.优先级高的进程先获取到资源,后续还会有源源不断的进程产生!
3.导致一个问题,自己程序的优先级较高导致常规进程(系统进程)获取不到资源(产生进程饥饿)
四:linux 进程调度与切换
1.其他概念:
1.竞争性:系统进程数目众多,并且cpu的资源只有一个,导致进程之间必然会产生竞争的关系,合理的竞争关系和资源分配所以产生了优先级!
2.独立性:多进程运行,每一个进程需要独享一个资源,多进程的运行互不干扰!
3.多个进程在多个cpu下同时的运行,这称之为并行。
4.多个进程在一个cpu下通过进程切换的方法,在一段时间里面,让多个进程都得以推进,这称之为并发。
2.进程切换:
1.进程切换是基于时间片进行轮转的方式进行推进多个进程。
3.进程调度:
1.cpu:中有许许多多的寄存器用来保存临时数据。
2.eax,ebx,ecx,edx, eip(pc指针,指向下一条程序的指针)。
3.跑一个进程:这个进程(数据+代码))就由寄存器保存。在cpu中的临时数据被称为硬件上下文。
4.一个进程的时间片已经到了那么程序没有运行完成当前已经执行的代码和产生的数据由对应进程的pcb保存起来!
5.下一个新的进程过来的时候通过赋值进行覆盖!
6.进程二次进行执行的时候代码和数据就直接从对应的pcb中去获取赋值到cpu上面。(二次调度)
五.环境变量:
1.mian函数参数(实现命令行的基础):
1命令行带参是实现linux下命令行参数的基础:
2.实现命令行参数是需要两个一个是 int argc 一个是 char* argv[] .
3.argc 用来保存argv中的char* 类型的数据的个数!
#include<stdio.h>
#include<stdlib.h>int main(int argc , char* argv[])
{for(int i=0;argv[i];i++){printf("%s\n",argv[i]);}return 0;
}
2.bash 获取命令行字符串是如何进行传参?
自己实现一个命令去进行加减乘除!
int main(int argc , char* argv[])
{if(argc == 4){int a=atoi(argv[2]);int b=atoi(argv[3]);if(strcmp(argv[1],"add")==0)printf("%d+%d=%d\n",a,b,a+b);else if(strcmp(argv[1],"sub")==0)printf("%d-%d=%d\n",a,b,a-b);else if(strcmp(argv[1],"rid")==0)printf("%d*%d=%d\n",a,b,a*b);else if(strcmp(argv[1],"dev")==0){if(b==0){printf("The dividend cannot be zero!\n");}else {printf("%d/%d=%d\n",a,b,a/b);}}}else{printf("user error: plase ./mybin [add|sub|rid|dev] a b\n");}return 0;
}
3.环境变量:
1.常见环境变量:
1.PATH:指定的命令搜索路径
2.HOME:当前用户的家目录也是登录进入的默认路径
3.SHELL当前shell 的路径一般是:/bin/bash
4. 命令:echo $环境变量名
2.如何把自己的程序变成不需要./就可以执行:
方法一:把当前可执行程序拷贝到系统的默认命令池中
方法二:把当前程序的路径添加到path这个环境变量中
3.注意:如果改变了path的默认路径这个操作是一次性的下一次打开服务器是回去默认值的!
3.环境变量相关命令:
1.echo $环境变量名 -------打印环境变量内容。
2.export 添加的环境变量名=路径 -------添加环境变量
3.env 查看当前的所有环境变量名称和路径
4.unset 变量名称 -------清除环境变量
5.set 显示本地定义的shell变量和环境变量!
4.代码获取环境变量:
1.命令行第三个参数!
2.通过bash进行管理保存的形式和argv 相同!
1.执行代码的效果和使用env命令相同!
int main(int argc , char* argv[],char* env[])
{for(int i=0;env[i];i++){printf("%s\n",env[i]);}return 0;
}
5.获取单个环境变量:
1.使用getenv()函数
2.函数参数是环境变量的名称返回的是路径!
2.使用:environ变量获取
3.需要通过extern 进行声明:
4.和遍历env的效果差不多!
6.通过环境变量对程序进行加密:
1.获取当前用户名称!
2.进行名称的比较!
3.只有root可以冒充其他用户,这个程序起到了一个加密操作!
60 int main()61 {62 char* tmp = getenv("USER");63 64 if(strcmp(tmp,"LIMO")==0)65 {66 printf("function()\n"); 67 }68 else69 {70 printf("This program doesn't belong to you!\n ");71 }72 return 0;73 }
7:本地变量和环境变量的区别!
1.如何去创建一个本地变量直接变量名称=变量内容
2.环境变量具有全局属性可以在父子之间进行继承。
3.本地变量只能通过echo $变量名称 打印本地变量内容。
4.在代码中的getenv函数获取不到本地变量!
5.只在bash中有效并且不可以被子进程去获取到!
4.环境变量一开始是从哪里获取到的?
1.bash 一旦登录就启动的!
2.在用户家目录下有一个 ./bash_profile 文件提供用户开始的环境变量!
3.可以改变给 ./.bash_profile 中添加内容可以让bash刚刚打开的时候就打印出我们想要的内容!
4.我们观察到其实.bash_profile中添加的环境变量不多主要都还在文件/etc/bashrc中!