本文涉及:
exec函数族
调度程序
execl()
execv()
exec函数族 exec函数族提供了一个在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新的进程替换了。另外,这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执行的脚本文件。
使用exec函数族主要有两种情况:
(1)当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用exec函数族中的任意一个函数让自己重生。
(2)如果一个进程想执行另一个程序,那么它就可以调用fork函数新建一个进程,然后调用exec函数族中的任意一个函数,这样看起来就像通过执行应用程序而产生了一个新进程。
使用man 3 exec
查看exec函数族帮助:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <unistd.h> int execl (const char *path, const char *arg, ...) ;int execlp (const char *file, const char *arg, ...) ;int execle (const char *path, const char *arg, ..., char * const envp[]) ;int execv (const char *path, char *const argv[]) ;int execvp (const char *file, char *const argv[]) ;int execvpe (const char *file, char *const argv[], char *const envp[]) ;
The exec() family of functions replaces the current process image with a new process image。意思为exec()函数族将当前进程映像替换为新的进程映像。可以理解为使用函数时,用指定程序(进程)替换当前进程的进程映像(程序正文段、数据段、堆和栈)。
使用C程序调度其他进程 程序设计中,服务程序通过exec()函数族,周期性的启动后台程序或者常驻内存的服务程序异常终止时,在短时间内重启它。
1.先执行fork函数,创建一个子进程,让子进程调用exec执行一个新的进程。
2.新进程将替换子进程,不会影响父进程
3.在父进程中,可以调用wait函数等待新进程运行结果,这样来实现调度功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> int main () { while (true ) { if (fork() == 0 ) { execl ("/usr/bin/ls" ,"/usr/bin/ls" ,"-lt" ,"/" ,(char *)0 ); exit (0 ); }else { int status; wait (&status); sleep (5 ); } } return 0 ; }
上述程序,每隔5秒调用一次ls
列出根目录下的文件。子进程调用execl
函数,如果成功,子进程映像被ls
进程映像替换,如果失败,执行exit(0)
结束执行,防止系统中存在大量不可控的子进程;父进程等待子进程退出,可以防止子进程成为僵尸进程。
下面给出完整的调度程序示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> int main (int argc,char *argv[]) { if (argc<3 ) { printf ("Using:./procctl timetvl program argv ...\n" ); printf ("Example:/project/tools/bin/procctl 5 /usr/bin/tar zcvf /tmp/tmp.tgz /usr/include\n\n" ); printf ("本程序是服务程序的调度程序,周期性启动服务程序或shell脚本。\n" ); printf ("timetvl 运行周期,单位:秒。被调度的程序运行结束后,在timetvl秒后会被procctl重新启动。\n" ); printf ("program 被调度的程序名,必须使用全路径。\n" ); printf ("argvs 被调度的程序的参数。\n" ); printf ("注意,本程序不会被kill杀死,但可以用kill -9强行杀死。\n\n\n" ); return -1 ; } for (int ii=0 ;ii<64 ;ii++) { signal (ii,SIG_IGN); close (ii); } if (fork()!=0 ) exit (0 ); signal (SIGCHLD,SIG_DFL); char *pargv[argc]; for (int ii=2 ;ii<argc;ii++) pargv[ii-2 ]=argv[ii]; pargv[argc-2 ]=NULL ; while (true ) { if (fork()==0 ) { execv (argv[2 ],pargv); exit (0 ); } else { int status; wait (&status); sleep (atoi (argv[1 ])); } } }