一、Z(zombie)-僵尸进程
1.僵尸进程概念
故事
张三每天都有跑步的习惯,这一天他和往常一样跑步,跑了两三圈,突然跑在它前面的一个人倒在地上不动了,作为热心市民张三赶紧报警并且拨打120。很快120就来了,但是没过几分钟就走了,这个人已经噶了(去世了),并交给了警察。警察这个时候会怎样做呢?警察立刻封锁了现场,并且叫来法医,法医确认了这个人的死亡原因,并且收集了所有信息。然后告诉家属信息。这个时候再把这个人抬走。
请问从这个人倒下到他被抬走,他是死亡状态吗?
不是,他是死亡了,但是他不是死亡状态,这个时候他是僵死状态,直到他被抬走他才是死亡状态。
- 僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用) 没有读取到子进程退出的返回代码时就会产生僵死(尸)进程。
- 僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。
- 所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态
2.僵死状态(进程处理)
解决方法
- 重启操作系统(建议不推荐)。
- 利用信号SIGCHLD,子进程状态改变后会向其父进程发送SIGCHLD信号。父进程在接受到该信号后,在信号处理函数中调用wait或者waitpid。
- 将僵尸进程的父进程杀掉,将最终使用的子进程变为孤儿进程,从而交由init进程处理其退出信息。
3.僵尸进程的危害
- 进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。可父进程如果一直不读取,那子进程就一直处于Z状态。
- 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存task_struct(PCB)中,换句话说, Z状态一直不退出, PCB一直都要维护。
- 那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间!
- 僵尸进程会导致内存泄漏。
4.僵尸进程的模拟实现
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
pid_t id = fork();
if(id < 0)
{
perror("fork");
return 1;
}
else if (id > 0)
{
printf("parent[%d] is sleeping...\n",getpid());
sleep(10);
}
else
{
// child进程
printf("child[%d] is begin Z...\n",getpid());
sleep(2);
exit(EXIT_SUCCESS);
}
return 0;
}
二、孤儿进程
1.孤儿进程的概念
父进程结束或者异常终止,但是子进程继续运行。此时子进程的PPID被设置为1,即init进程。init进程接管了该子进程,并等待它结束,在父进程退出之后,子进程退出之前,该子进程属于孤儿进程
2.模拟实现孤儿进程
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t id = fork();
if (id < 0)
{
// 创建失败
perror("fork");
return 1;
}
else if (id == 0)
{
// child
while (1)
{
printf("I am child, pid : %d\n", getpid());
sleep(1);
}
}
else
{
// father
printf("I am father, pid : %d\n", getpid());
sleep(10);
exit(0);
}
return 0;
}
三、进程优先级
1.进程优先级基本概念
2.查看系统进程
使用 ps -al 命令
3.PRI and NI
为啥Linux进程的优先级要有数值范围?
- 操作系统要较为均匀的调度进程,每个进程都要得到调度。
- 如果一个进程的优先级太大(太小),就会导致一直占用cpu(一直得不到调度---->进程饥饿)
- 需要强调一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化。
- 可以理解nice值是进程优先级的修正修正数据。
4.查看进程优先级的命令(top)
用top命令更改已经存在进程的nice值
进入top后按“r”–>输入进程PID–>输入nice值。
5.为啥要有优先级
四、环境变量
1.环境变量基本概念
- 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数。
- 如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
- 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。
2.为什么需要环境变量
环境变量(envirnment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数。
3.常见的环境变量
4.查看环境变量的方法
5.测试PATH
创建hello.cpp文件
#include<iostream>
int main()
{
std::cout<<"Hello world"<<std::endl;
return 0;
}
编译后运行
我们分别带路径和不带路径运行,发现带路径就可以运行,而不带路径无法运行。
这个时候就有个问题?
为什么有些指令可以直接执行(例如ls、cd等等),不需要带路径,而我们的二进制程序需要带路径才能执行?
如果我们的程序所在路径加入环境变量PATH当中会发生什么呢?
我们发现确实不用带路径就可以运行了 。这个时候我们又有问题了。
为啥这个时候有可以不带路径了,我只是把mybin的路径加入到环境变量中而已?
6.环境变量的组织方式
在C语言中我们学到了指针数组,就是存放指针的数组,那么存放的就是各种环境变量的首地址,通过找到环境变量的首地址就可以找到对于的环境变量。
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串。
7.和环境变量相关的命令
- echo: 显示某个环境变量值。
- export: 设置一个新的环境变量。
- env: 显示所有环境变量。
- unset: 清除环境变量。
- set: 显示本地定义的shell变量和环境变量。
8.通过代码如何获取环境变量
1.命令行三个参数
#include<stdio.h>
int main(int argc,char* argv[],char* env[])
{
//argc : 命令行参数的个数, 本质上就是argv数组的元素个数
//argv :具体的命令行参数
// envp : 环境变量的值
int i = 0;
for(i=0;i<argc;i++)
{
printf("%s\n",argv[i]);
}
for(i=0;env[i]!=NULL;i++)
{
printf("%s\n",env[i]);
}
return 0;
}
2.通过第三方变量environ获取
#include<stdio.h>
int main(int argc,char* argv[])
{
extern char** environ;
for(int i=0;environ[i]!=NULL;i++)
{
printf("%s\n",environ[i]);
}
return 0;
}
3.系统调用getenv和putenv函数
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
printf("%s\n",getenv("PATH"));
return 0;
}