zoukankan      html  css  js  c++  java
  • linux 进程学习笔记-运行新进程

    我们知道,当用fork启动一个新进程以后,新进程会复制父进程的大部份内存空间并接着运行父进程中的代码,如果我们使新进程不运行原父进程的代码,转而运行另外一个程序集中的代码,这就相当于启动了一个新程序。 
    
    所以,要运行一个新程序,需要最基本的两步: 
    
    Ÿ 创建一个可运行程序的环境,也就是进程。 
    
    Ÿ 将环境中的内容替换成你所希望的,也就是用你希望运行的可执行文件去覆盖新进程中的原有映像,并从该可执行文件的起始处开始执行。  
    
    要做到第一点,非常简单,fork函数就可以;而要做到第二点,则可以利用exec函数族。 
    
      
    
    exec是一族函数的简称,包含在<unistd.h>中,它们作用都一样,用一个可执行文件覆盖进程的现有映像,并转到该可执行文件的起始处(main)开始执行。 
    
    原型如下: 
    
    int execl(const char *path, const char *arg0, ... /*, (char *)0 */);  
    
    int execlp(const char *file, const char *arg0, ... /*, (char *)0 */);  
    
    int execle(const char *path, const char *arg0, ... /*, (char *)0, 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[]); 
    
      
    
    我们先以最简单的execl函数为例,其他的大同小异。其第一个参数path是可执行文件的路径,是绝对路径;从arg0参数开始及后面所有的是你要传递给可执行文件的命令行参数。最后有一个注释/*, (char*)0 */是提醒我们最后一个参数应该传空字符串。如何函数运行成功,则不会有任何返回值,否则返回-1,而具体的错误号会被设置在errno,errno是一个全局变量,用于程序设置错误号。  
    
      
    
    看下面的例子: 
    
    #include <stdio.h>     
    
    #include <unistd.h>    
    
    int main () 
    
    { 
    
        printf("app start...
    "); 
    
    
    
    
        execl("/bin/ls", "/bin/ls", "-l",NULL); 
    
    
    
    
        printf("app end
    "); 
    
         
    
        return 0; 
    
    } 
    
    我们运行了bin目录下的ls程序,参数arg0时ls程序本身路径,arg1为-l,使得其以列表的形式列举当前目录,在我的计算机上程序输出如下: 
    
    app start... 
    
    total 12 
    
    -rw-r--r-- 1 zhouyh zhouyh  273 2011-06-20 11:09 temp.c 
    
    -rwxr-xr-x 1 zhouyh zhouyh 7175 2011-06-20 11:09 temp.exe 
    
    ls程序运行成功了。 
    
    但注意到了吗?没有输出“app end”这个字符串,原因很简单,我们没有新起进程,而是直接用ls程序覆盖了main函数所在的进程。 
    
      
    
    如果我们使用fork先启一个新进程,当其成功创建后(返回值为0),我们用execl来加载ls程序到新进程并运行之: 
    
    #include <stdio.h>   
    
    #include <unistd.h>   
    
    
    
    
    int main () 
    
    { 
    
        printf("app start...
    "); 
    
         
    
        if(fork() == 0) 
    
        { 
    
            execl("/bin/ls", "/bin/ls", "-l", NULL); 
    
        } 
    
             
    
        printf("app end
    "); 
    
         
    
        return 0; 
    
    } 
    
    程序的输出如下: 
    
    app start... 
    
    app end 
    
    zhouyh@ubuntu:~/Documents$ total 12 
    
    -rw-r--r-- 1 zhouyh zhouyh  229 2011-06-20 11:29 temp.c 
    
    -rwxr-xr-x 1 zhouyh zhouyh 7211 2011-06-20 11:30 temp.exe 
    
    程序的所有输出都OK了,但有一点可能和我们想象的不一样,那就是“app end”这个字符串很早就输出了而不是在最后,其实这并没有错,“app end” 是main函数所在的程序(temp.exe)即将结束时输出的,而列举文件目录的ls却完全在另外一个进程中,两个异步执行的进程,它们没有谁先谁后结束可言。(如果我们希望所有工作完成之后,即ls也执行玩以后,才输出“app end”,那么可以使用wait以及waitpid函数,“进程控制”中会讲,也可以参考我的 
    
      
    
    现在回过头来看除execl外的其他几个函数 : 
    
      
    
    int execlp (const char *file, const char *arg0, ... /*, (char *)0 */); 
    
    execlp和execl差不多,但区别在于前者会去系统环境变量查找file所指的程序的位置,所以如果通过环境变量能找到可执行文件,则file可以不是绝对路径了,比如 execlp("ls", "ls", "-l", NULL); 
    
      
    
    int execle (const char *path, const char *arg0, ... /*, (char *)0, char *const envp[]*/);  
    
    与execlp不同的是,其最后一个参数作为你自定义的环境变量参数传进去,而不是查找系统环境变量 
    
    char *env[] = { "HOME=/usr/home", "LOGNAME=home",(char *)0 }; 
    
    execle("/bin/ls", "ls", "-l", NULL, env); 
    
      
    
    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[]); 
    
    这三个函数和前面的三个类似,函数名由后缀l变成了v,其表达的含义是参数不再用参数列表传递而是用一个参数数组argv[],当然,数组最后一个元素也必须是char* 0  
    
      
    
    名字这么相近的函数,很容易混淆,可以从l,v,p,e 这样的后缀来区分: 
    
    l:参数为一个逗号分隔的参数列表,并以char* 0作为列表结尾 
    
    v: 参数为字符串数组,数组的最后一个元素为char* 0 
    
    p: 可以通过系统环境变量查找文件位置 
    
    e:调用者显示传入环境变量 
    
      
  • 相关阅读:
    lambda函数
    linux 自学系列:wc命令
    linux 自学系列:chmod 权限操作
    linux 自学系列:创建、删除目录、移动、更名文件或目录
    linux 自学系列:vi、vim编辑工具
    《架构之美》学习随笔:设计第一步
    安装memcache 时提示error while loading shared libraries: libevent2.0解决办法
    《架构之美》学习随笔:保证质量
    linux 自学系列:环境变量设置
    logging模块学习笔记:logger 对象、日志等级
  • 原文地址:https://www.cnblogs.com/zendu/p/4990729.html
Copyright © 2011-2022 走看看