这几天进度实在是有点慢(摇摇头~~),好啦,今天把第八章剩下的内容都搞定吧!
exec族(这里用了个族,包括七个函数)怎么工作呢?我们来看看:
The exec() family of functions replaces the current process image with a new process image. (一语中的)
比如说fork了一个子进程,开辟了一个新的空间,然后,我们在子进程(if(pid == 0){ ... })中执行exec。这个时候,exec在不创建新进程(ID当然也不会变)的情况下,调用一个新的程序,从新程序的main开始执行,替换了当前这个子进程的.text, .data, .bss, heap, stack。懂了吧~
具体有哪7个exec函数呢?我们先看定义;在定义之后,把他们的关系图也贴出来,一目了然;最后给出一段代码示例:
#include <unistd.h> int execl(const char *pathname, const char *arg0, ... /* (char *)0 */ ); int execv(const char *pathname, char *const argv[]); int execle(const char *pathname, const char *arg0, ... /* (char *)0, char *const envp[] */ ); int execve(const char *pathname, char *const argv[], char *const envp[]); int execlp(const char *filename, const char *arg0, ... /* (char *)0 */ ); int execvp(const char *filename, char *const argv[]); int fexecve(int fd, char *const argv[], char *const envp[]); /*All seven return: −1 on error, no return on success*/它们有什么区别呢?
(1) 注意它们7个的第一个argument,前四个是pathname,接下来两个是filename(*p),最后一个是fd(f*);
(2) 注意参数表的传递,l(list), v(vector);
(3) 以e结尾的3个函数(environment),可以传递一个环境指针(char **或char * [])。
细节就不说了,看关系图:
看它们,只有execve是system call,其他6个都是library function。exec执行前后real user ID不变,effective user ID取决于它们所执行程序文件的set user ID。(group ID类似)
最后看代码:
#include "apue.h" #include <sys/wait.h> char *env_init[] = {"USER=unkown", "PATH=/tmp", NULL}; int main(void) { pid_t pid; if((pid = fork()) < 0) { err_sys("fork error"); } else if (pid == 0) /*special pathname, special environment*/ { if(execle("/home/liuzch/workspace/echoall", "echoall", "myarg1", "MY ARG2", (char *)0, env_init) < 0) err_sys("execle error"); } if(waitpid(pid, NULL, 0) < 0) err_sys("wait error"); if((pid = fork()) < 0) { err_sys("fork error"); } else if (pid == 0) { /*special filename, inherit environment*/ if (execl("/home/liuzch/workspace/interp", "interp", "only 1 arg", (char *)0) < 0) err_sys("execlp error"); } exit(0); }
(1)echoall是输出参数的c文件编译后,将a.out重命名得到的;interp是interpreter file,解释器文件和解释器的解释看这里:http://blog.csdn.net/shiquxinkong/article/details/10228609;
(2)第一个fork之后的execle的实现;
(3)第二个fork之后execl的实现,第一个参数指向了file descriptor,它的内容是
#!/home/liuzch/workspace/echoall fromInterp
那么最终输出的时候,argv[0]=/home/liuzch/workspace/echoall; argv[1]=fromInterp; argv[2]=/home/liuzch/workspace/interp(其后依次是execl中的argv)。(我跑的时候一直显示permission denied,为什么呢?The initial argument for these functions is the pathname of a file which is to be executed.所以说echoall是可执行的,interp也必须是可执行的。既然permission denied,那么把interp文件改成可执行的就可以啦!)
接下来8.11之后的内容简单记录一下提纲,用到再查:
8.11 changing user IDs and group IDs
8.13 system function:ISO C 定义,对操作系统依赖性很强,用于调用shell中的命令,具体用法man一下即可。
8.14 accounting process:进程终止时写一个account 记录。
8.16 进程调度:每个进程有个nice值,nice值越小,优先级越高。
下面是长长的分割线
————————————————————————————————————————————————————————
第八章结束,主要介绍了进程的fork,exit,waitpid和exec,很经典,期待第九章~