1、execve函数
在父进程中fork一个子进程,在子进程中调用execve函数启动新的程序,代替
原有进程,被执行进程的PID不会改变。例子代码如下:
int main(int arg, char *args[])
{close(STDOUT_FILENO);//关闭标准输出
open("/dev/pts/1", O_WRONLY);//打开"/dev/pts/1",做为标准输出
pid_t pid = fork();//调用fork产生一个子进程
int status;
if (pid == -1)
{
printf("fork failed\n");
return 0;
}
if (pid == 0)//子进程调用execve,执行ls -l命令
{
char *args[] = { "/bin/ls", "-l", NULL };
execve("/bin/ls", args, NULL);
}
else
{
return 0;//父进程退出
}
}
2、僵死进程
父进程没有调用wait,子进程就退出了,这个时候子进程就成了僵死进程。
int main(int arg, char *args[])
{
pid_t pid = fork();//调用fork之后会有两个进程
int status;
if (pid == 0)
{
printf("child begin\n");
sleep(5);
printf("child end\n");
return -1;
}
if (pid > 0)
{
printf("parent begin\n");
wait(&status);//阻塞调用,直到子进程退出,wait才返回
printf("child return = %d\n", WEXITSTATUS(status));
printf("parent end\n");
}
return 0;
}
3、孤儿进程
父进程在调用wait或者waitpid之前就已经退出的子进程。此时init进程成为子进程的父进程。
如:
int main(int arg, char *args[])
{
pid_t pid = 0;
pid = fork();
if (pid == 0)
{
while(1)
{
printf("child\n");
sleep(1);
printf("ppid = %d\n", getppid());
}
}
if (pid > 0)
{
exit(0);
}
return 0;
}
4、结束进程一个进程由以下5个原因中的一个终止。
1)main函数调用了return;
2)调用了exit;
3)调用了_exit;
4)调用了abort函数;
5)被一个信号终止。
前三个是正常终止,后两个是非正常终止。无论进程如何终止,最后都执行相同的内核代码,关闭打开的文件,释放内存资源和其他清理工作。
return和exit的区别:
在主函数中一样,在子函数中,return只是子函数退出到主函数,退出码只能从主函数得到;若想在子函数中也得到退出码,则用exit。
abort函数:
当碰到一个很严重内存不足这样的错误,无法用程序的方式处理时再使用abort。
kill函数:
用kill函数杀死一个进程,杀死进程用SIGKILL信号,例子如下:
int main(int arg, char *args[])
{
if(arg > 1)
{
int pid = atoi(args[1]);
kill(pid,SIGKILL);
}else
{
printf("pid = %u\n", getpid());
sleep(100);
}
return EXIT_SUCCESS;
}