目录
进程
基本解释:
基本概念:程序的一个执行实例,正在执行的程序等。
内核观点:担当分配系统资源的实体。
描述进程PCB:
进程的信息被放在一个叫作进程控制块的数据结构中,可以理解为进程的属性集合
简称为PCB(process control block),Linux操作系统中的PCB是:task struct
task_struct:
在linux中描述进程的结构体叫做task_struct,是linux内核的一种结构,会被装载到RAM里并且包含进程信息
内容分类:
- 标识符:描述本进程的唯一标识符,用来区别其他进程
- 状态:任务状态,退出代码,退出信号等。
- 优先级:相对于其他进程的优先级
- 程序计数器:程序中即将被执行的下一条指令的地址
- 内存指针:包括程序代码和进程相关数据的指针,还有其他进程共享的内存块的指针
- 上下文数据:进程执行时处理器的寄存器中的数据
- I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表
- 其他信息
查看进程:
ps aux 是用BSD的格式来显示 这个进程
显示的项目有:USER , PID , %CPU , %MEM , VSZ , RSS , TTY , STAT , START , TIME , COMMAND
ps -ef 是用标准的格式显示这个进程
显示的项目有:UID , PID , PPID , C , STIME , TTY , TIME , CMD
“|” 管道符:是将前面命令输出作为管道后面命令的输入
grep:一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。
通过系统调用获取进程标识符
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<sys/types.h>
4 int main()
5 {
6 printf("pid %d \n",getpid());
7 printf("ppid %d \n",getppid());
8 return 0;
9 }
- getpid(),返回当前进程pid
- geppid(),返回当前进程父进程pid
- 子进程与父进程代码段相同,但是数据各自独有。
通过系统调用创建进程(fork)
fork的特点在于它被调用一次 ,却返回两次,它可能有三种不同的返回值(创建出错返回-1,父进程返回值的子进程id,子进程返回的0)
1:父子进程代码共享,私有一份(采用写时拷贝)
2:fork有两个返回值,fork的返回值起到分流的作用。我们的用户通过fork的返回值来判断,到底哪个进程是父进程,哪个是子进程。
———对于父进程来说返回自是子进程的id(创建出错失败返回-1)
————对于子进程来说返回值是0(创建出错失败无子进程)
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<sys/types.h>
4 int main()
5 {
6 int ret = fork();
7 if(ret < 0)
8 {
9 perror("fork error\n");
10 return 1;
11 }
12 else if(ret == 0)
13 {
14 printf("this is child ,ret:%d,pid:%d\n",ret,getpid());
15 }
16 else
17 {
18 printf("this is father ,ret:%d.ppid:%d\n",ret,getppid());
19 }
20 sleep(1);
21 return 0;
22 }
进程状态
为了知道正在运行的进程是什么含义,我们需要知道进程是什么状态?
- R运行状态:它表明进程要么在运行中,要么在运行队列中。
- S睡眠状态: 意味着进程等待事件完成(也叫做可中断睡眠)
- D磁盘休眠状态:这个状态的进程通常会等待IO的结束(也叫不可中断睡眠)
- T停止状态:可以通过发送SIGSTOP信号来停止进程,这个被暂停的进程可以通过SIGCONT信号让进程继续运行
- X死亡状态:只是一个返回状态,不会在任务列表中看见这个状态
- (t追踪状态)
僵尸进程
Z(zombie)僵尸状态是一个比较特殊的状态。当进程退出并且父进程没有读取到子进程的返回码时就会产生僵尸进程
僵尸进程会以终止状态保持在进程表中,并且会一直等待父进程读取退出状态码
只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态
僵尸进程产生原因:
0:子进程先于父进程退出
1:进程退出为了保存自己退出的原因,因此这个退出后资源不会
被完全释放。等待父进程来获取退出状态,然后释放子进程所有资源
2:假如父进程没有关心子进程的退出,那么这时候退出子进程将成为一个僵尸进程
僵尸进程危害
资源泄漏,正常进程可能无法创建
- 进程的退出状态必须被维持下去,因为它要传递给父进程信息,可父进程一直不读取,那子进程就一直处于Z状态
- 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说,Z状态一直不退出,PCB就一直维护
- 父进程创建很多子进程不回收,会造成内存资源浪费,因为数据结构对象本身就要占用内存
创建一个维持30秒僵尸进程的例子
1 #include<stdio.h>
2 #include<stdlib.h>
3
4 int main()
5 {
6 pid_t pid = fork();
7 if(pid < 0)
8 {
9 printf("error\n");
10 return -1;
11 }
12 else if(pid == 0)
13 {
14 printf("child %d is z...\n",getpid());
15 }
16 else
17
18 { printf("parent %d\n",getppid());
19 sleep(30);
20 }
21 return 0;
22 }
维持僵尸的例子:
1 #include<stdio.h>
2 #include<errno.h>
3 #include<unistd.h>
4 #include<stdlib.h>
5 int main()
6 {
7 pid_t pid;
8 pid = fork();
9 if(pid < 0)
10 {
11 perror("fork");
12 exit(0);
13 }
14 else if(pid == 0)
15 {
16 exit(0);
17 }
18 else
19 {
20 while(1)
21 {
22 printf("I am zombie\n");
23 sleep(1);
24 }
25 }
26 return 0;
27 }
kill -9 也不能杀死僵尸
孤儿进程
父进程先退出,子进程就称为“孤儿进程”
这个孤儿进程将被孤儿院 (1号进程)init进程所领养,子进程退出后将由init进程来收回资源,因此孤儿进程并不会有什么危害。
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<errno.h>
4 #include<unistd.h>
5
6 int main()
7 {
8 pid_t pid = fork();
9 if(pid < 0)
10 {
11 perror("fork error");
12 }
13 if(pid == 0)
14 {
15 printf("this is child,pid:%d\n",getpid());
16 //输出进程id
17 //睡眠五秒,保证父进程先退出
18 sleep(5);
19 printf("child:pid:%d,ppid:%d\n",getpid(),getppid());
20 printf("child process is exited\n");
21 }
22 else
23 {
24 printf("this is father,pid:%d\n",getpid());
25 //父进程睡眠一秒,保证子进程输出进程id
26 sleep(1);
27 printf("father process is exited\n");
28 }
29 return 0;
30 }
进程优先级
- cpu资源分配的先后顺序,就是指进程的优先权
- 优先权高的进程有优先执行权利,配置进程优先权对多任务环境的linux很有用,可以改善系统性能
- 还可以吧进程运行在指定的CPU上,大大改善整体性能
交互式进程:优先级高
批处理进程:优先级低
PRI:进程的优先级,越小越早执行
NI:nice值,表示进程可被执行的优先级修正值 -20~19 一共四十个级别(renice)
(nice为负值时,优先级值会变低,即优先级会变高)
PRI(new) = PRI(old)+ nice
(nice值不是进程的优先级,但是进程nice值会影响到进程优先级变化,可以理解为nice是优先级修正数据)
修改进程优先级的命令
- nice
- renice
启动前调整:nice
开始执行程序就指定nice值:nice -n -5 ./test
调整已经存在的进程的nice:renice
renice -5 -p PID
- 竞争性:系统进程数目众多,而CPU资源只有少量,所以进程之间是有竞争属性的,为了高效完成任务,跟合理竞争相关资源,便有了优先级
- 独立性:多进程运行,需要独享各自资源,多进程运行期间互不干扰
- 并行:多个进程在多个CPU下分别,同时进行运行,这称之位并行
- 并发:多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都能够推进,称之为并发
环境变量
基本概念::一般是指在操作系统中用来指定操作系统运行环境的一些参数。如:我们在编写c++代码时,在链接的时候,从来不知道我们所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。(环境变量通常具有某些特殊功能,还有在系统中通常具有全局特性)
———— 环境变量相当于给系统或用户设置一些参数,不同的环境变量其不同的作用,“Path”就是一个变量里面存储了一些常用命令所存放的目录路径。用来告诉系统, 当要求系统运行一个程序而没有告诉它程序所在的完整路径时, 系统除了在当前目录下面寻找此程序外, 还应到哪些目录下去寻找
常见环境变量
- PATH*:指定命令的搜索路径
- HOME*: 指定用户的主工作目录(及用户登录Linux系统时,默认的目录)
- HISTSIZE*: 指保存历史命令记录的条数
- SHELL*: 当前shell,它的值通常是/bin/bash
查看环境变量的方法:echo $环境变量名称
相关的命令
- echo:显示某个环境变量值
- export:设置一个新的环境变量
- env:显示所有环境变量
- unset:清除环境变量
- set:显示本地定义的shell变量和环境变量
- 每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以‘\0’结尾的环境字符串。
- 常用getenv和putenv函数来访问特定的环境变量
- 环境变量通常是全局变量,可以被子进程继承下去