回收子进程、
当一个进程由于某种原因终止时,内核并不是立即把它从系统中删除,它仍然消耗系统资源,保持在一种已终止的状态中,这种进程被称作僵死进程。
当父进程执行回收,内核将子进程的退出状态传递给父进程,抛弃已终止的子进程后,此进程才不存在了。
如果父进程没有回收它的僵死进程就终止了,那么内核会安排init
进程(PID=1)去回收它们。长时间运行的进程应当主动回收它们的僵死进程。
我们可以调用waitpid
函数来等待它的子进程终止或者停止。默认情况下(options=0时),waitpid
挂起调用进程,直到它的等待集合的一个子进程终止。如果等待集合中的一个进程在刚调用的时候就已经终止了,那么waitpid
就立即返回。waitpid
返回的值是导致其返回的已终止的子进程的PID。
pid_t waitpid(pid_t pid, int &status, int options)
- pid
- pid > 0:等待集合是一个单独的PID=pid的进程。
- pid = -1:所有子进程。
- pid < -1:|pid|进程组中任何子进程。
- pid = 0:当前进程同一进程组中任何子进程。
- option
- WNOHANG:若无子进程结束也会返回(返回值为0),不会挂起当前进程。
- WUNTRACED:若等待集合中一个进程被停止也返回。
- WCONTINUED:若等待集合中一个进程收到SIGCONT从停止重新开始也返回。
注意,程序不会按照特定的顺序回收子进程。
wait()函数:
我们应当知道的是,在用fork创建子进程后,父子进程的执行的先后顺序是不定的,这时,我们可以用wait函数,wait()会暂停当前进程的执行,直到有信号到来或者子进程结束。总的来说,wait()的作用就是阻塞父进程,等待子进程。
我们是在父进程中使用wait(),可以不让父进程先于其产生的子进程结束,因为如果父进程结束了,而子进程还没有结束,那这个进程就会变成一个“孤儿进程”,他会被init进程收养(进程号为1),并由init进程对它们完成状态收集工作。
当然如果子进程结束了,但是父进程没有调用wait或者waitpid(),那么子进程的资源就无法得到收集释放,这时候的子进程被称为“僵尸进程”,会占用系通资源,是非常不好的,危害很大。
函数原型:pid_t wait(int *status)
函数参数:
①status作为一个整形值,用来保存子进程退出时的状态;
②如果status为NULL,表示忽略子进程退出时的状态;
③如果status不为空,wait函数会将子进程退出的状态存入status中,另外,子进程退出时的状态可以通过linux中的特定的宏(macro)来进一步测定退出状态。
返回值:
成功,返回子进程的进程号;失败,返回-1
加载并运行程序、
int execve(char *filename, char *argv[], char *envp[])
execve
函数加载并运行可执行目标文件filename
,且带参数列表argv
和环境变量envp
。
execve
函数覆盖当前进程的代码、数据、栈,有相同的PID,继承已打开的文件描述符和信号上下文。
execve
函数调用一次从不返回,除非出现错误例如找不到filename
,才会返回到调用程序。
execve调用失败返回-1,成功不返回。
#include<iostream>
using namespace std;
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdio.h>
int main()
{
fork();
char* argv[] = {"/usr/bin/ls","-lh","/root",nullptr};
char*envp[] = {0,nullptr};
if(execve(argv[0],argv,envp) < 0)
{
cout << "error" << endl;
exit(0);
}
return 0;
}
上述代码执行的功能是创建一个子进程,然后子进程和父进程都使用命令 /usr/bin/ls -lh /root
Comments NOTHING