建站专业定制,炫酷wordpress主题,wordpress如何导出,天津网站建设网络1. 操作系统的进程状态2. Linux操作系统的进程状态3. 僵尸进程4. 孤儿进程5. 进程优先级5.1. 优先级是什么和为什么要有优先级5.2. Linux中的进程优先级 6. 进程切换7. 环境变量7.1. 环境变量的认识7.2. 环境变量相关的命令7.3. 环境变量和本地变量7.4. 命令行参数7.5. 获取环境… 1. 操作系统的进程状态2. Linux操作系统的进程状态3. 僵尸进程4. 孤儿进程5. 进程优先级5.1. 优先级是什么和为什么要有优先级5.2. Linux中的进程优先级 6. 进程切换7. 环境变量7.1. 环境变量的认识7.2. 环境变量相关的命令7.3. 环境变量和本地变量7.4. 命令行参数7.5. 获取环境变量7.6. 环境变量学习小总结 1. 操作系统的进程状态
运行状态 程序运行到内存的时候可以称该程序是一个进程。操作系统为该进程创建了一个PCB是给CPU管理使用的。进程有很多而CPU只有一个所以一旦进程多了就需要等待。CPU中有一个运行队列当进程处于运行队列的时候可以称该进程处于运行状态。
阻塞状态 当进程1想要访问磁盘的时候磁盘还有其他进程尚未处理完毕所以让进程1进入磁盘的PCB的等待队列中此时称进程1的状态为阻塞状态。假设不把进程1放进等待队列中那么进程1只能处于CPU的运行队列中就是让CPU等待这是很不合理的。因为CPU的处理速度很快而磁盘的处理速度相对于CPU比较慢不可能等待处理速度慢的磁盘。
例如你电脑的硬件处理速度很烂比如说是磁盘那么当你访问磁盘的时候会有卡顿这个卡顿其实可以理解为所谓的阻塞状态。
挂起状态 如上图所示这里有4个进程都是要访问磁盘的进程1访问磁盘磁盘尚未处理结束需要进程1等待那么此时进程1进入阻塞状态。然后进程2也要访问磁盘进程3也是进程4也是…那么2、3、4进程都是阻塞状态。此时处于阻塞状态的进程太多了处于阻塞状态意味着内存里面都要保存着进程的相关数据然而此时内存空间不足了于是操作系统就把其他处于阻塞状态的2、3、4进程的相关数据放到磁盘的某个空间存储用以减少内存空间的开销。这样的进程的状态称为挂起状态。如下图所示。 进程的相关数据被保存了起来但是进程依然存在于内存这样减少了内存空间的开销而进程也因PCB的存在等待被重新唤回。
2. Linux操作系统的进程状态
Linux操作系统的进程状态一般有以下7种状态下面逐一讲解一下。 运行状态
Linux操作系统进程的运行状态的字母是R。下面用一段代码来查看Linux操作系统下的进程的运行状态。
1 #include stdio.h2 3 int main()4 {5 while(1); 6 return 0;7 }当运行起来的时候输入查看进程状态ps axj | head -1 ps axj | grep “process”的指令即可看到。 阻塞状态
阻塞状态在Linux操作系统中代表的字母是S。下面用一段代码来查看Linux操作系统下的进程的阻塞状态。 1 #include stdio.h2 #include unistd.h3 4 int main()5 {6 int cnt 0;7 while(1)8 {9 printf(value %d\n,cnt);10 sleep(1); 11 }12 return 0;13 }当进程运行的时候我们观察一下它的进程状态。 原因是代码中有printf函数该函数是向显示器打印那么也就是说该进程占用显示器资源。而CPU很快一下子就可以把命令执行完成但是显示器相对应CPU处理速度不快所以该进程的运行时间里99%都是阻塞状态1%是运行状态。所以当我们查看进程状态的时候大概率是阻塞状态。
暂停状态
暂停状态在Linux操作系统中代表的字母是T。下面用一段代码来查看Linux操作系统下的进程的暂停状态。
1 #include stdio.h2 3 int main()4 {5 while(1); 6 return 0;7 }代码运行起来进程就是运行状态此时我们输入相关命令使得进程的状态变为暂停状态。 恢复运行状态 进程重新恢复运行状态。
前台进程与后台进程
#include stdio.h2 #include unistd.h3 4 int main()5 {6 int cnt 0;7 while(1)8 {9 printf(value %d\n,cnt);10 sleep(1); 11 }12 return 0;13 }以上面这段代码为例来看一下前台进程与后台进程。
前台进程 像这样不能接受命令的进程称之为前台进程只能由crtl c中止。
后台进程
当像上面正在运行的进程暂停过后然后又重新启动此时进程的状态虽然也是运行状态但是却与上面进程的运行状态有所不同。 深度睡眠状态
深度睡眠状态在Linux操作系统中代表的字母是D。下面用一段代码来查看Linux操作系统下的进程的深度睡眠状态。
这个状态不好演示很容易把系统搞崩。所以直接用语言描述。
假如一个进程A它的任务就是往磁盘里写入大量数据但是由于磁盘的读取速度比较慢那么此时进程A就一直占用着资源。后来越来越多的进程进入内存导致内存空间的资源吃紧。于是操作系统开始排查发现进程A什么都没在干而是一直占用资源于是把进程A干掉了。后来进程A被干掉之后磁盘读取数据任务完成出来发现进程A不见了无法交差但是手头上的数据也不能一直拿着所以直接扔了。
后来用户来查看原来要存放在磁盘的数据发现数据不见了。于是乎便盘问了操作系统进程A磁盘。磁盘说我只是个干活的让我干啥就干啥。进程A说我也是个干活的突然间有个家伙要把我干了我也没办法。操作系统说我的任务就是维护好资源的分配所以只能把进程A干掉。
用户觉得谁也没有错于是制定相关的规定。给予某个重要的进程一个免死金牌例如进程A当资源吃紧的时候操作系统不能杀死带有免死金牌的进程。那么此时这个带有免死金牌的进程就会进入深度睡眠状态此时这个进程不能被杀死只能等进程本身自己醒来或者物理断电解决进程。
一句话总结处于深度睡眠状态的进程操作系统是杀不掉的只能等进程自己醒来或者物理断电。
追踪暂停状态
追踪暂停状态在Linux操作系统中代表的字母是t。下面用一段代码来查看Linux操作系统下的进程的追踪暂停状态。 1 #include stdio.h2 3 int main()4 {5 printf(hello world\n);6 printf(hello world\n);7 printf(hello world\n);8 printf(hello world\n);9 printf(hello world\n);10 printf(hello world\n);11 printf(hello world\n);12 printf(hello world\n);13 printf(hello world\n);14 printf(hello world\n); 15 return 0;16 }当我将这段代码运行起来并调试的时候就可以清楚地看到这个追踪暂停状态。 3. 僵尸进程
僵尸状态
将状态在Linux操作系统中代表的字母是Z。用一个例子浅浅的认识一下僵尸状态。
一天小明在路上看到有一个人躺在地上噶了此时小明选择了报警。警察来了之后封锁了现场并且叫来了法医进行验尸。此时尸体会有一段时间用来被检验并等待结果最终宣告死亡。
切换到进程的角度一个进程退出了其中资源并不会马上被回收而是保留一段时间等待父进程或者操作系统读取。其中这段等待被回收的状态可以称该进程的状态是僵尸状态。或者可以说该进程没有被父进程或者操作系统回收也可称该进程是僵尸进程。
如何创建僵尸进程呢那就是确保父进程正常运行子进程直接退出。
来看代码 ⮂⮂ buffers 1 #include stdio.h 2 #include unistd.h 3 #include stdlib.h 4 int main() 5 { 6 pid_t id fork(); 7 if(id 0) 8 { 9 //child10 printf(i am a child process,process id is :%d,parent id is :%d\n,getpid(),getppid());11 sleep(3);12 exit(1); 13 } 14 else 15 { 16 //parent17 while(1) 18 { 19 printf(i am a parent process,process id is :%d,parent id is :%d\n,getpid(),getppid());20 sleep(1); 21 } 22 } 23 return 0; 24 } 僵尸进程是无法被杀死的因为它已经退出了已经退出了的进程是杀不死的。但是它的pcb还存着等待父进程读取然后回收。如果父进程不回收那么就会导致内存泄漏。
4. 孤儿进程
孤儿进程顾名思义就是父进程死了但是子进程还在跑。这样的进程称为孤儿进程。
下面来看一段代码看看是如何生成孤儿进程的。
#include stdio.h
#include unistd.h
#include stdlib.h
int main()
{ pid_t id fork(); if(id 0) { //child while(1) { printf(i am a child process,process id is :%d,parent id is :%d\n,getpid(),getppid()); sleep(1); } } else { //parent while(1) { printf(i am a parent process,process id is :%d,parent id is :%d\n,getpid(),getppid()); sleep(1); } } return 0;
}如果操作系统不领养该进程该进程退出的时候变成了僵尸将会没有人给它收尸。而操作系统作为一个管理角色必须对其进行处理。
用一句话总结被领养的进程我们可以称该进程是孤儿进程。
如果是前台进程创建的子进程那么该子进程变为孤儿进程后将会变成后台进程此时只能用kill命令杀掉该进程。
5. 进程优先级
5.1. 优先级是什么和为什么要有优先级
优先级的概念
优先级其实就是排队的先后优先级在生活中很常见例如食堂排队打饭面试工作时懂XX技术优先这些都是常见的优先级。
为什么要有优先级
那么为什么要有优先级呢是因为资源是有限的例如饭堂打饭饭如果打完了那么优先级低的人就吃不到饭例如面试时懂XX技术的优先级高那么有可能优先级低的人就无法获取这份工作…
5.2. Linux中的进程优先级
在Linux中进程的优先级本质就是PCB上的一个数字。就好比你生活中去一家餐厅吃饭因为位置不多所以需要排队如果你愿意等下去服务员就会给你一个排队的号码这个号码就是你的优先级。
下面创建一个进程并输入相关的指令(ps - la)查看进程优先级。
最终进程优先级 老的优先级(固定80) nice值 可以用top工具更改进程的优先级主要是通过更改nice值 注意nice值的范围是[-20,19],所以最小是-20最大是19。所以进程的最终优先级的范围是[80-20, 8019]
6. 进程切换
假设你的电脑只有1个CPU那么就会有很多进程占用CPU的资源。但是当用起来的时候就感觉进程都是一起运行的。例如你可以同时打开qq微信同时在qq和微信上发消息。这是因为操作系统采用进程切换的方法让多进程在宏观上运行的时候像是一起运行的实际在微观上是串行的。
具体点就是操作系统会给多个进程分配时间片当某个进程的时间片用完了那么该进程就是被操作系统拿下切换另一个进程运行。这个时间是很短很短的所以我们一般感觉不出来。
对时间片的概念可以举这么一个例子A要考研他不可能说先把数学学完了再去学英语然后再去学专业课。一般考研的都是今天给数学分配多少时间给英语分配多少时间给专业课分配多少时间。在这个分配好的时间片里无论你数学完成的怎么样我数学的时间片到了我就得切换到英语科目去学习。最后到考研结束那么数学也能学完英语也能学完专业课也能学完。 把学习数学想象成是一个进程1学习英语是进程2学习专业课是进程3小A是一个CPU这就可以类比到计算机的进程切换的概念中去。
那么进程的切换是怎么完成的下面来浅浅地认识一下。
先来看一个例子
A是一名大学生他突然有一天想去服兵役然后就报名参加了当兵。报名后A向学校说明了他的情况学校学籍处给他保留了相应的学籍。当A两年义务兵结束后选择继续回归校园。此时退伍回来后A就向学校学籍处拿回自己的学籍然后就重新恢复了自己大学生的身份。
切换到计算机的世界。A是一个进程当A进程去使用打印机资源的时候那么CPU中的相关的寄存器就会给进程A保留了相关的数据。当进程A完成了打印的任务回到了原来的轨道。此时进程A回来后A就会拿到原来寄存器里的相关数据继续运行自己的进程。 7. 环境变量
7.1. 环境变量的认识
环境变量其实可以认为是一个字符串常见的环境变量有PATH,HOME,SHELL…每个环境变量都是为了应付不同的应用场景的。
PATH
当我们在命令行输入各种指令的时候是否有想过为什么直接输入就可以执行相应的操作呢而当我们写好了一个代码运行的时候却要在可执行程序的前面指定好路径呢
其实命令行的指令也是指定好了路径的这个行为是环境变量帮我们完成的。 如果想要我们自己写的代码也能不加路径直接运行也有方法。
将test拷贝到/usr/bin/配置环境变量 当我们在命令行输入相关的指令bash进程都会去PATH底下逐一查找查看这些目录下有没有该命令如果有则运行没有则提示找不到。 那么我们只需要把我们代码的路径添加到PATH中那么运行的时候我们就不用加路径了。 环境变量可以帮助我们在运行相应的指令的时候让指令识别路径身份认证等操作。
例如
#include stdio.h
#include string.h
#include stdlib.h
int main()
{ //获取当前user的环境变量char* name getenv(USER); if(strcmp(name,root) 0) { printf(%s %s\n,name,root); } else { printf(%s %s\n,name,name); } return 0;
} 当我是用户1的身份运行时 当我是root身份运行时 所以环境变量的用途有很多它不仅可以帮我们识别路径也可以帮我们识别用户身份等等…
用背单词的例子来理解环境变量。 7.2. 环境变量相关的命令
echo命令
操作显示某个环境变量
示范 env
操作显示所有的环境变量
示范 set命令
操作显示本地变量
示范 export命令
操作设置一个新的环境变量
示范 unset命令
操作清除某个环境变量
示范 7.3. 环境变量和本地变量
环境变量具有全局性无论你在哪里用都可以。而本地变量只能当前进程用。
用背单词的例子来认识 是因为子进程继承了父进程的时候顺便继承了环境变量所以才说环境变量具有全局性。
7.4. 命令行参数
C语言中的main函数是可以带有参数的例如
int main(int argc, char* argv[])
{return 0;
}那么带了参数又有什么用呢 #include stdio.h2 #include string.h3 #include stdlib.h4 int main(int argc, char* argv[])5 {6 for(int i 0; i argc; i)7 {8 printf(argv[%d]---%s\n,i,argv[i]); 9 }10 return 0;11 }运行结果 所以我们之前学习的命令为什么带上选项可以有不同的功能就是因为命令行参数的存在。
#include stdio.h
#include string.h
#include stdlib.h
int main(int argc, char* argv[])
{ if(argc ! 2) { printf(Usage: \n\t%s [-a/-b/-c/-ab/-bc/-ac/-abc]\n, argv[0]); return 1; } if(strcmp(-a, argv[1]) 0) { printf(功能a\n); } if(strcmp(-b, argv[1]) 0) { printf(功能b\n); } if(strcmp(-c, argv[1]) 0) { printf(功能c\n); } if(strcmp(-ab, argv[1]) 0) { printf(功能ab\n); } if(strcmp(-bc, argv[1]) 0) { printf(功能bc\n); } return 0;
}运行结果 可以简单的认为在命令行上执行的程序的程序名就是argv[0]后面带上的选项就是argv[i]。
7.5. 获取环境变量
系统接口getenv()
这里就是简单的系统调用就不再展示了上面的有一段代码是写过的。
char* env[]
main函数中可以有三个参数其中第三个参数就是环境变量它同char* argv[] 一样都是一个指针数组数组的元素都是char类型的最后一个char是NULL因此我们可以将它打印出来。 #include stdio.h2 #include string.h3 #include stdlib.h4 int main(int argc, char* argv[], char* env[])5 {6 for(int i 0; env[i]; i)7 {8 printf(env[%d]----%s\n,i,env[i]); 9 }10 return 0;11 }运行结果 extern char* environ
在Linux中提供一个二级指针指向了一个保存环境变量的char*[]因此我们只需要在代码中声明该变量也可以打印出所有的环境变量。
#include stdio.h
#include string.h
#include unistd.h
#include stdlib.h
int main()
{ extern char** environ; for(int i 0; environ[i]; i) { printf(env[%d]----%s\n,i,environ[i]); } return 0;
} 运行结果 7.6. 环境变量学习小总结
什么是环境变量
环境变量简单的来说就是字符串它可以帮助用户识别路径识别用户的身份等等操作。
环境变量具有全局性本地变量具有局部性。具体可以参看背单词的例子。
命令行参数
当我们在命令行输入指令的时候操作系统和shell是怎么认识的就是通过main函数的参数来识别的。其中我们输入的命令行会被操作系统和shell放到一个char* 数组里面用来解析我们的各种命令。
如何获取环境变量
参考3.5所讲的内容。