进程就是一个pcb(process control block),是操作系统对运行中程序的描述,通过这个描述实现对运行中程序的调度管理,Linux下pcb是一个task_struct结构体,task_struct是Linux内核的一种数据结构。
包括内存指针,上下文数据,程序计数器,进程标识符(pid),进程状态,优先级,IO信息等
在知道进程概念的基础上,我们再来看一个进程的创建
pid_t fork(void);//创建一个子进程fork具有两个返回值,因此在创建子进程之后,我们通常使用if来对父子进程进行分流,返回值为0表示子进程,返回值大于0表示父进程(也就是说对于父进程返回的子进程pid)。 比如下面的代码示例:
int main() { pid_t pid; pid = fork(); if (pid < 0) //返回值<0, 表示出错 { perror("fork error~~~\n"); return -1; } else if (pid == 0) //返回值为0,是子进程进入的判断 { printf("i am child~~~~\n"); } else //返回值大于0,是父进程进入的判断 { printf("i am parent~~~~\n"); } return 0; }为了弄明白正在运行的进程是什么意思,我们需要了解进程的不同状态。 进程状态可以大体上分为以下5种: R 运行状态:并不意味着程序一定在运行,它表示的是程序要么在运行中,要么在运行队列里。 S 可中断休眠态:意味着进程在等待事件完成(能够被一些中断唤醒的休眠状态) D 不可中断休眠态:也叫磁盘休眠状态,处于这个状态的进程通常会等待IO结束(不能被中断唤醒的休眠状态,只能等待条件满足之后自动唤醒) T 停止状态:当前不再运行,什么都不做(可以通过给进程发送SIGSTOP信号 来停止进程,这个被停止的进程也可以通过发送SIGCONT让进程继续运行) Z 僵死状态:进程已经退出,但是资源没有完全释放
进程状态查看:ps -aux
在此基础上,引出僵尸进程的概念,这需要我们重点去理解! 首先,什么是僵尸进程?僵尸进程是如何产生的?资源没有完全释放又是什么意思?僵尸进程有什么危害?以及僵尸进程该如何处理?
僵尸进程就是指处于僵死状态的进程(Z),该进程已经退出不在运行,但是资源并没有完全释放
僵尸进程的产生是由于子进程先于父进程退出,并且父进程并没有关注到子进程的退出状态,此时子进程就会变成一个僵尸进程
我们可能会去思考,子进程退出的时候,为什么不直接释放掉相关资源,这样不就不会产生僵尸进程了吗?这其实也就是我们下面要提到的,也就是子进程退出后,资源没有完全释放是什么意思! 其实,子进程在退出的时候会保存退出原因,子进程要告诉父进程自己为什么退出了,如果父进程没有关注到子进程的退出原因,子进程就会一直保存自己的退出原因,导致资源无法完全释放。 进一步,由于用户所能创建的进程数量是有限的,并且资源没有完全回收是会占据内存资源的,这也就是僵尸进程的危害,导致资源泄露
处理僵尸进程的方法 最为简单直接的就是退出父进程,子进程保存退出原因就是为了给父进程看的,既然父进程已经退出了,那么子进程保存退出原因也就没有意义了,因此父进程退出之后,子进程的资源也就释放了。
除此之外,我们常用的方法是进程等待,由于父进程对于子进程的退出默认是忽略,因此我们可以使用进程等待,让父进程等待并关注子进程的退出,回收子进程的资源,获取子进程的退出信息。 wait方法
pid_t wait(int* status);返回值:成功返回被等待的进程pid,失败则返回-1 参数:输出型参数,通过该参数获取子进程的退出状态,如果不关心子进程的退出状态,只是为了防止僵尸进程的产生,可以置为NULL。
waitpid方法
pid_t waitpid(pid_t pid, int* status, int options);返回值:正常返回时会返回收集到的子进程的pid 如果设置了 WNOHANG(非阻塞等待),调用如果没有发现有子进程退出则返回0 出错返回-1
参数:pid == -1,表示等待任意一个子进程,此时与wait类似 pid > 0,表示等待指定的子进程退出 status 输出型参数,表示获取子进程退出状态 options:设置为WNOHANG表示非阻塞等待,调用如果没有发现有子进程退出则返回0 设置为0,表示阻塞等待,没有子进程退出就一直等下去
调用waitpid之后我们可以使用
WIFEXITED(status);//若为正常终止子进程返回的状态,则为真。(可查看进程是否正常退出) WEXITSTATUS(status);//若果WIFEXITED(status)为真,可提取子进程退出码。(用来查看子进程的退出码)总结 如果子进程已经退出,调用wait/waitpid,会立即返回,并且释放资源,获得子进程退出信息。 如果任意时刻调用wait/waitpid,子进程存在并且还在运行,wait会阻塞等待直到子进程退出,waitpid若使用WNOHANG则不会阻塞,直接返回0,若设置为0,则阻塞等待。 等待的子进程不存在,直接报错返回。