Linux 进程创建二(execve和wait)

三:execve系统调用
int execve(const char *filename, char *const argv[],char *const envp[]);
fork创建了一个新的进程,产生一个新的PID
execve用被执行的程序完全替换了调用进程的映像。
execve启动一个新程序,替换原有进程,所以被执行进程的PID不会改变。
execve函数接受三个参数
--path    要执行的文件完整路径
--argv    传递给程序完成参数列表,包括argv[0],它一般是执行程序的名字,最后一个参数一般是NULL
--envp    是指向执行execed程序的环境指针,一般设为NULL

 

//execve函数的定义
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

int main(int arg, char * args[])
{
    /*
      第一个参数是程序的名字,第二个参数是被调用程序的参数,最后一个参数必须是NULL
      这个跟main函数的参数args数组很相似
     */
    char * argv[]={"/bin/ls","-l",NULL};
    execve("/bin/ls",argv,NULL);
    /*
     execve函数是替换原来的程序代码,但是进程PID不会变,文件描述符不会变,只是程序代码被替换了
     所以execve函数后面的语句都不会被执行
     */
    printf("program is end!\n");
    return 0;
}

 

wait和waitpid函数可以收集子进程的退出状态
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
stauts保存子进程的退出状态(本质上就是子进程的返回值,但是我们不能直接查看这个返回值,必须用宏定义转化一下)
在waitpid函数中,参数pid是等待进程的PID,他能够接受一下四种值
    "<-1"    等待任何PGID等于PID的绝对值子进程
    "-1"    等待任何子进程(这个进程创建的子进程)
    "0"    等待任何PGID等于调用进程的子进程
    ">0"    等待PID等于pid的子进程    

 

//wait函数的定义
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int arg, char * args[])
{
    pid_t child=0;
    int status=0;
    child=fork();
    if(child==-1)
    {
        printf("system is game over!\n");
        return -1;
    }
    if(child==0)
    {
        //in child process
        printf("child is begining!\n");
        sleep(3);
        printf("child is end , now is your turn!\n");
    }else{
        //in parent process
        printf("parent is begining , i am wait my son!\n");
        wait(&status);
        printf("child status=%d\n",WEXITSTATUS(status));
        printf("my son is end , now i am go !\n");
    }
    printf("all is end!\n");
    return 10;
}

 

 

 

用fork或者execve函数创建一个新进程,为了收集新进程的退出状态并且防止出现僵死进程(zombie process),父进程应该调用wait或者waitpid函数等待进程终止。

 

僵尸进程
一个僵尸进程是在父进程退出之前就终止的子进程(子进程在父进程之前终止,此时因为父进程还没有退出,所以系统会保留子进程的pid,退出
状态,返回给父进程有wait函数,如果父进程没有wait函数,系统就会一直保持子进程的PID等信息,直到父进程退出)
之所以被称为僵死进程是因为他虽然死掉了,但依然在进程表中存在。
子进程退出后分配给他的内存和其他资源都被释放,但是子进程还在内核进程表保留一条,内核在父进程回收子进程的退出状态前一直保留它。
有一个两个僵死进程不算什么问题,但一旦一个程序频繁执行fork或者execv却又不能收集退出状态,那么最终将会填满进程表(内核进程表是有上限的),这会影响性能,可能导致系统重启

 

 

孤儿进程
孤儿进程是一个父进程在调用wait或者waitpid之前就已经退出了(即父进程在子进程之前退出)。此时init进程成为子进程的父进程。
init进程成为子进程的父进程,收集子进程的退出状态,从而避免出现僵死进程。
注意:任何一个进程都必须有父进程,init的父进程是0号进程,父进程与子进程是相对独立的(子进程会拷贝进程控制器和代码区,写时拷贝数据区),父进程退出,子进程不一定会退出

 

posted on 2016-08-28 09:01  寒魔影  阅读(4874)  评论(0)    收藏  举报

导航