学习进程之前,先了解一下程序:所谓程序就是指编译好的二进制文件,在磁盘上,不占用系统资源(cpu、内存.....)
而进程是与操作系统相关,是指在内存中运行起来的程序,占用一些系统资源,每当一个程序运行,就相应产生一个进程。进程的一些相关信息被放在一个叫进程控制块的数据结构中,称之为PCB。
Linux下的PCB是task_struct,其中的一些成员:
- 标示符(PID):表示进程ID,系统中用其来表示某一个进程的名称
- 状态:进程处于初始化、就绪、运行、挂起、退出等状态
- 优先级(RPI):程序被cpu执行的优先顺序,值越小,越先被执行,可以通过nice(程序运行前指定)/renice(调整已存在的进程)进行修改
- 记录当前工作目录、描述虚拟地址空间的信息、用户ID和用户组ID
- umask掩码,默认权限:读、写、执行的权限,可以通过chmod修改 ------->
环境变量:
指在操作系统中用来指定操作系统运行环境的一些参数,相当于一个指针。可以用查看这些环境变量
- PATH:指定可执行文件搜索路径
- SHELL:指定当前所使用的命令解析器
- HISTSIZE:保存历史命令记录的条数
- HOME:指定用户主目录
getenv函数:获取环境变量值
char *getenv(const char *name); 成功:返回环境变量的值;失败:NULL (name不存在)
setenv函数:设置环境变量的值
int setenv(const char *name, const char *value, int overwrite);
返回值:成功:0;失败:-1
参数overwrite取值: 1:覆盖原环境变量 0:不覆盖。
unsetenv函数:删除环境变量name的定义
int unsetenv(const char *name); 成功:0;失败:-1
进程控制(进程创建、进程终止,进程等待)
其中进程等待最主要的原因就是为了防止僵尸进程的危害。
僵尸进程产生原因:在创建一个进程的时候,1.fork( ),会返回两次,一次进入父进程(返回值=子进程pid),一次进入子进程(返回值=0),2.在fork()的调用处,整个父进程空间会原模原样地复制到子进程中,包括指令,变量值,程序调用栈,环境变量,缓冲区,等等。当子进程想要退出的时候,若父进程没有wait( )或waitpid( )获取子进程的退出码,子进程的状态会变为Z状态(僵尸进程)。设置成僵尸进程的原因是维护子进程的信息,以便父进程在以后的某个时间获取。而当父进程终止,有子进程是僵尸状态的,那么僵尸进程的父进程ID就变为1(init进程)。
僵尸进程的危害:若一直等待父进程获取它的退出原因,而父进程一直没有获取,那么这个子进程将一直以僵尸状态一直存在;系统还要一直维护子进程的PCB(因为其中存储着进程的退出状态等信息);若有多个僵尸进程,还会占用内存,造成资源的浪费;内存泄漏。应该用wait/waitpid来获取其退出状态,避免产生僵尸进程。
linux下查看进程的命令:查看进程:ps 实时更新:top 查找僵尸进程:ps -aux|grep Z 杀死一个进程:kill -9 PID
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4
5 int main()
6 {
7 pid_t i = fork();
8 if(i == -1)
9 {
10 printf("fork error");
11 }
12 if(i == 0)
13 {
14 printf("%d",getpid());
15 exit(0); //结束子进程
16 }
17 else
18 {
19 printf("parent jincheng ");
20 sleep(600); //等待600s,父进程才结束,有足够时间可以看子进程状态
21 }
22
23 }
可以看到有一个僵尸进程:
1.可以用wait阻塞等待任意子进程退出,返回其PID,
2.也可以用waitpid等,-1为等待任意进程,也可以指定进程的PID,WNOHANG设置非阻塞等,0时,阻塞等待。
孤儿进程:
父进程先于子进程退出,而子进程仍然运行,子进程就是孤儿。进程来看下面子进程等待600s时,父进程非阻塞witpid,所以可以exit(0)结束。子进程就变成了孤儿进程。
可以看到子进程PID
来看一下子进程的详细信息
因为15077的父进程已经退出,而操作系统会将孤儿进程通过init(PID==1)进程来管理,等进程结束后,回收资源。