进程和人类一样,都有产生、生长、睡眠和死亡等各种生命形态。其中,函数fork创建新的进程,函数exec执行新的程序,函数sleep休眠正在执行的进程,函数wait同步进程, exit结束进程,进程就死亡了。
(1) fork - exec
调用fork创建的子进程,将共享父进程的代码空间,复制父进程的进程数据空间, 如堆栈等。调用exec函数后,将会使用新程序的代码覆盖进程中原来的程序代码,并使进程使用函数提供的命令行参数和环境变量去执行新的程序。
exec函数族有六个函数如下:
#include <unistd.h>
int execl(const char *path, const char *arg0, ..., (char *)0);
int execle(const char *path, const char *arg0, ..., (char *)0, char *const envp[]);
int execlp(const char *file, const char *arg0, ..., (char *)0);
int execv(const char *path, const char *argv[]);
int execve(const char *path, const char *argv[], const char *envp[]);
int execvp(const char *file, const char *argv[]);
extern char **environ;
如何用fork-exec方式执行程序'uname -a?
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t pid;
if((pid = fork()) == 0){
fprintf(stderr, "---- begin ----/n");
// sleep(3); // 睡眠3秒会导致子进程成为僵死进程
execl("/bin/uname", "uname", "-a", 0);
fprintf(stderr, "---- end ----/n");
}
else if(pid > 0)
fprintf(stderr, "fork child pid = [%d]/n", pid);
else
fprintf(stderr, "Fork failed./n");
return 0;
}
[bill@billstone Unix_study]$ gcc exec1 -o exec1
[bill@billstone Unix_study]$ ./exec1
---- begin ----
Linux billstone 2.4.20-8 #1 Thu Mar 13 17:18:24 EST 2003 i686 athlon i386 GNU/Linux
fork child pid = [13276]
[bill@billstone Unix_study]$ ./exec1
---- begin ----
fork child pid = [13278]
[bill@billstone Unix_study]$ Linux billstone 2.4.20-8 #1 Thu Mar 13 17:18:24 EST 2003 i686 athlon i386 GNU/Linux
(2) vfork-exec
vork比起fork函数更快,二者的区别如下:
(a) vfork创建的子进程并不复制父进程的数据,在随后的exec调用中系统会复制新程序的数据到内存。
(b) 父进程以vfork方式创建子进程后将被阻塞,直到子进程推出或执行exec调用后才能继续运行。
当进程只用来执行新程序时,vfork-exec模型比fork-exec模型具有更高的效率,这种方法也是shell创建新进程的方式。
//exec2.c
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t pid;
if((pid = vfork()) == 0){
fprintf(stderr, "---- begin ----/n");
sleep(3);
execl("/bin/uname", "uname", "-a", 0);
fprintf(stderr, "---- end ----/n");
}
else if(pid > 0)
fprintf(stderr, "fork child pid = [%d]/n", pid);
else
fprintf(stderr, "Fork failed./n");
return 0;
}
[bill@billstone Unix_study]$ gcc exec2.c -o exec2
[bill@billstone Unix_study]$ ./exec2
---- begin ----
fork child pid = [13293]
[bill@billstone Unix_study]$ Linux billstone 2.4.20-8 #1 Thu Mar 13 17:18:24 EST 2003 i686 athlon i386 GNU/Linux
(3) system
在UNIX中,我们也可以使用system函数完成心程序的执行。
nt system(const char * string); 函数说明 system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,此命>令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。 返回值 =-1:出现错误 =0:调用成功但是没有出现子进程 >0:成功退出的子进程的id 如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-1。若参数string为空指针(NULL),则返回非零值>。如果system()调用成功则最后会返回执行shell命令后的返回值,但是此返回值也有可能为 system()调用/bin/sh失败所返回的127,因此最好能再检查errno 来确认执行成功。 附加说明 在编写具有SUID/SGID权限的程序时请勿使用system(),system()会继承环境变量,通过环境变量可能会造成系统安全的问题。
//exec3.c
#include <unistd.h>
#include <stdio.h>
int main()
{
char cmd[] = {"/bin/uname -a"};
system(cmd);
return 0;
}
[bill@billstone Unix_study]$ gcc exec3.c -o exec3
[bill@billstone Unix_study]$ ./exec3
Linux billstone 2.4.20-8 #1 Thu Mar 13 17:18:24 EST 2003 i686 athlon i386 GNU/Linux
[bill@billstone Unix_study]$