本章目录
- 1.孤儿进程
- 2.状态优先级
- 3.环境变量
1.孤儿进程
父进程如果提前退出,那么子进程后退出,进入Z之后,那该如何处理?
父进程先退出,子进程还在,子进程就称之为“孤儿进程”。
孤儿进程被1号init进程(系统本身)领养,为什么要被领养?未来子进程退出的时候,父进程早已不在,需要领养进程来进行回收。
1 #include <stdio.h>
2 #include <unistd.h>
3
4 int main()
5 {
6 pid_t id = fork();
7 if(id == 0)
8 {
9 //child
10 while(1)
11 {
12 printf("hello child process\n");
13 sleep(1);
14 }
15 }
16 else
17 {
18 //father
19 int cnt = 5;
20 while(cnt)
21 {
22 printf("I am father process:%d\n",cnt--);
23 sleep(1);
24 }
25 }
26 return 0;
27 }
此时父进程已经退出,子进程的ppid变成1了。
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
1 29525 29524 28262 pts/2 28262 S 1001 0:00 ./mytest3
2.状态优先级
基本概念:
CPU资源分配的先后顺序,就是指进程的优先级
优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。
[jyf@VM-12-14-centos 进程]$ ps -la | head -1 && ps -la | grep mytest4
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 1001 9546 29568 5 80 0 - 1054 n_tty_ pts/3 00:00:06 mytest4
我们可以发现几个很重要的信息:
UID:代表执行者的身份
PRI:代表这个进程可被执行的优先级,其值越小越早被执行
NI:代表这个进程的nice值
PRI and NI
PRI也是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高
NI,即我们所要说的nice值了,其表示进程可被执行的优先级的修正数据
PRI值越小越快被执行,那么加入nice值后,将会使的PRI变为:PRI(new) = PRI(old)(指的是每次该PRI,此处的值都是最初的那个,而不是改了的) + nice
这样,当nice值为负数的时候,那么该进程的优先级值将会变小,即其优先级将会变高,则其越快被执行
所以,调整进程优先级,在Linux下,就是调整进程nice值
nice其取值范围是-20至19,一共40个级别。
PRI vs NI
需要强调的一点的是,进程的nice值不是进程的优先级,它们不是一个概念,但是进程nice值会影响到进程的优先级变化。
可以理解nice值是进程优先级的修正数据。
如何改进程的nice值,进而改进程的优先级呢?
普通用户改进程优先级,可以输入top命令,回车再输入r,回车在输入进程的pid,回车,在输入nice值,回车,优先级是等于最初的优先级+nice值,如果nice值为负数,即提高进程的优先级,要用sudo或root权限呀。
当然优先级不建议更改,系统自己安排的会更好一些,当然特殊情况除外。
其他概念:
竞争性:系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。
独立性:多进程运行,需要独享各种资源,多进程运行期间互不干扰
并行:多个进程在多个CPU下采用分别,同时进行运行,这称之为并行
并发:多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。
3.环境变量
基本概念:
环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数。
如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
环境变量通常具有某些特殊用途,还有在系统当中通常具有全局属性
常见的环境变量
PATH:指定命令的搜索路径
HOME:指定用户的主工作目录(即用户登陆到Linux系统中时,默认的用户,家目录)
SHELL:当前的shell,它的值通常是/bin/bash。
大家有没有想过这样一个问题,为什么我们自己写到程序运行的时候在当前目录下要带./xxx,即带路径才能运行,而shell的系统命令带不带路径都能运行??
因为系统命令在环境变量的目录中,我们自己的不在,在环境变量中的命令,系统会进行查找识别。
查看环境变量的方法
echo $NAME //NAME:你的环境变量名称
[jyf@VM-12-14-centos 进程]$ echo $PATH 查看环境变量的值的内容
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/jyf/.local/bin:/home/jyf/bin
像 ls,pwd等是在/usr/bin目录中的。
比如:我们想自己写到程序运行也像系统命令一样,只需将自己的程序所在的路径加到环境变量中即可。
[jyf@VM-12-14-centos 进程]$ pwd
/home/jyf/进程
[jyf@VM-12-14-centos 进程]$ export PATH=$PATH:/home/jyf/进程(自己程序所在的路径)
[jyf@VM-12-14-centos 进程]$ myproc //看这样就直接可以运行了
I am parent process:pid :20132
ret:20133,pid:20132,ppid:28262
ret:0,pid:20133,ppid:20132
在命令行上改环境变量,只在本次登陆有效,退出重进后就没了,前提是在没有改配置文件的,改了配置文件是会有影响的
统计自己历史写了多少条目录,上限3000.
[jyf@VM-12-14-centos 进程]$ history | wc -l
788
和环境变量相关的命令
1.echo:显示某个环境变量值
2.export:设置一个新的环境变量
3.env: 显示所有环境变量
4.unset:清除环境变量
5.set:显示本地定义的shell变量和环境变量
我们在shell上单独定义的变量叫做局部变量。
环境变量的组织方式
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境变量字符串。
通过代码获得环境变量
1.命令行的第三个参数获取
1 #include <stdio.h>
2 #include <unistd.h>
3
W> 4 int main(int argc,char* argv[],char* env[])
5 {
6 printf("begin.......................\n");
7 for(int i=0;env[i];i++)
8 {
9 printf("env[%d]:%s\n",i,env[i]);
10 }
11 printf("end..........................\n");
12 }
2.系统给我们提供的全局变量 extern char** environ;第三方变量获取
1 #include <stdio.h>
2 #include <unistd.h>
3
W> 4 int main(int argc,char* argv[],char* env[])
5 {
6 int i =0 ;
7 printf("begin.......................\n");
8 extern char** environ;
9 for(i = 0; environ[i];i++)
10 {
11 printf("env[%d]:%s\n",i,environ[i]);
12 }
13 printf("end..........................\n");
14 return 0;
15 }
libc中定义全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时要用extern声明。
获得某个环境变量的值:getenv()
int main()
{
printf("%s\n",getenv("PATH"));
return 0;
}
export:
[jyf@VM-12-14-centos 进程]$ export year=2023
[jyf@VM-12-14-centos 进程]$ env | grep year
year=2023
子进程的环境变量是从父进程来到,默认,所有的环境变量,都会被子进程继承,环境变量具有全局属性
[jyf@VM-12-14-centos 进程]$ y=2023 //shell局部变量
[jyf@VM-12-14-centos 进程]$ echo $y
2023
main函数三个参数中前2个参数的意思
main(int argc,char* argv[ ],char* env[ ]);
我们已经知道第三个参数叫做命令行参数,那前两个呢?叫做命令行参数。
> 17 int main(int argc,char* argv[],char* env[])
18 {
19 int i=0;
20 for(i=0;i<argc;i++)
21 {
22 printf("argv[%d]:%s\n",i,argv[i]);
23 }
24 return 0;
25 }
1 #include <stdio.h>
2 #include <unistd.h>
3
W> 4 int main(int argc,char* argv[],char* env[])
5 {
6 if(argc==1)
7 {
8 printf("Usage:%s 至少要有一个选项\n",argv[0]);
9 return 1;
10 }
11
E> 12 if(strcmp("-a",argv[1]) == 0)
13 {
14 printf("这个是功能一\n");
15 }
E> 16 else if(strcmp("-b",argv[1]) == 0)
17 {
18 printf("这个是功能二\n");
19 }
20 return 0;
21 }
结果:
[jyf@VM-12-14-centos 进程]$ ./mytest6
Usage:./mytest6 至少要有一个选项
[jyf@VM-12-14-centos 进程]$ ./mytest6 -a
这个是功能一
[jyf@VM-12-14-centos 进程]$ ./mytest6 -b
这个是功能二
命令行参数的意义:可以让我们同样的一个程序,通过选项的方式,选择使用同一个程序的不同子功能,这就是选项的含义,这些选项的底层都是命令行参数完成的,通过父进程传给子进程的。
到这就结束了哦,2023新年快乐!!!