zoukankan      html  css  js  c++  java
  • exec

     

    说是exec系统调用,实际上在Linux中,并不存在一个exec()的函数形式,exec指的是一组函数,一共有6个,分别是:

    #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 execve(const char *path, char *const argv[], char *const envp[]);
    
    其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。
    exec函数族的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个可执行文件。这里的可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件。

    与一般情况不同,exec函数族的函数执行成功后不会返回,因为调用进程的实体,包括代码段,数据段和堆栈等都已经被新的内容取代,只留下进程ID等一些表面上的信息仍保持原样,颇有些神似"三十六计"中的"金蝉脱壳"。看上去还是旧的躯壳,却已经注入了新的灵魂。只有调用失败了,它们才会返回一个-1,从原程序的调用点接着往下执行。

    现在我们应该明白了,Linux下是如何执行新程序的,每当有进程认为自己不能为系统和拥护做出任何贡献了,他就可以发挥最后一点余热,调用任何一个exec,让自己以新的面貌重生;或者,更普遍的情况是,如果一个进程想执行另一个程序,它就可以fork出一个新进程,然后调用任何一个exec,这样看起来就好像通过执行应用程序而产生了一个新进程一样。

    事实上第二种情况被应用得如此普遍,以至于Linux专门为其作了优化,我们已经知道,fork会将调用进程的所有内容原封不动的拷贝到新产生的子进程中去,这些拷贝的动作很消耗时间,而如果fork完之后我们马上就调用exec,这些辛辛苦苦拷贝来的东西又会被立刻抹掉,这看起来非常不划算,于是人们设计了一种"写时拷贝(copy-on-write)"技术,使得fork结束后并不立刻复制父进程的内容,而是到了真正实用的时候才复制,这样如果下一条语句是exec,它就不会白白作无用功了,也就提高了效率。

    /* exec.c */
    #include <unistd.h>
    main()
    {
    	char *envp[]={"PATH=/tmp",
    			"USER=lei",
    			"STATUS=testing",
    			NULL};
    	char *argv_execv[]={"echo", "excuted by execv",	NULL};
    	char *argv_execvp[]={"echo", "executed by execvp", NULL};
    	char *argv_execve[]={"env", NULL};
    	if(fork()==0)
    		if(execl("/bin/echo", "echo", "executed by execl", NULL)<0)
    			perror("Err on execl");
    	if(fork()==0)
    		if(execlp("echo", "echo", "executed by execlp", NULL)<0)
    			perror("Err on execlp");
    	if(fork()==0)
    		if(execle("/usr/bin/env", "env", NULL, envp)<0)
    			perror("Err on execle");
    	if(fork()==0)
    		if(execv("/bin/echo", argv_execv)<0)
    			perror("Err on execv");
    	if(fork()==0)
    		if(execvp("echo", argv_execvp)<0)
    			perror("Err on execvp");
    	if(fork()==0)
    		if(execve("/usr/bin/env", argv_execve, envp)<0)
    			perror("Err on execve");
    }
    

    程序里调用了2个Linux常用的系统命令,echo和env。echo会把后面跟的命令行参数原封不动的打印出来,env用来列出所有环境变量。

    由于各个子进程执行的顺序无法控制,所以有可能出现一个比较混乱的输出--各子进程打印的结果交杂在一起,而不是严格按照程序中列出的次序。

    编译并运行:

    $ cc exec.c -o exec
    $ ./exec
    executed by execl
    PATH=/tmp
    USER=lei
    STATUS=testing
    executed by execlp
    excuted by execv
    executed by execvp
    PATH=/tmp
    USER=lei
    STATUS=testing
    
  • 相关阅读:
    ExtJS小技巧
    Oracle 表的行数、表占用空间大小,列的非空行数、列占用空间大小 查询
    NPM 私服
    IDEA 不编译java以外的文件
    SQL 引号中的问号在PrepareStatement 中不被看作是占位符
    Chrome 浏览器自动填表呈现淡黄色解决
    批量删除Maven 仓库未下载成功.lastupdate 的文件
    Oracle 11g 监听很慢,由于监听日志文件太大引起的问题(Windows 下)
    Hibernate 自动更新表出错 建表或添加列,提示标识符无效
    Hibernate 自动更新表出错 More than one table found in namespace
  • 原文地址:https://www.cnblogs.com/xiayong123/p/3717489.html
Copyright © 2011-2022 走看看