嵌入式LinuxC编程之进程控制(二)

来源:互联网 发布:在线教学软件 编辑:程序博客网 时间:2024/05/16 11:33
承接上一节所写内容,首先通过fork()和vfork()函数创建子进程,子进程与父进程执行的代码是相同的。通常创建了一个进程,目的是为了执行与父进程不同的操作,实现不用的功能,有错引进了exec()函数族。
一、exec()函数族:
    1、有六个exec开头的函数组成
  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,const char *argv[]);
  int execve(const char *path,const char *argv[],char *const envp[]);
  int execvp(const char *file,const char *argv[]);
  这些函数都定义在函数库中,在使用前需包含头文件<sys/types.h>和<unistd.h>,并且在预定义时定义一个外部的全局变量 extern char **environ;
  其作用就是,定义完此命令,可在当前目录执行系统程序,如同执行vim一样。
  exec()函数族中的函数,都实现对子进程的数据段、代码段和堆栈段进行替换的功能,如果调用成功,则加载新程序,没有返回值。如果出错返回-1.
2、如何记住exec函数的区别:
  (1) 函数名中带有p:代表文件的绝对路径(或称相对路径),当函数中带有p时可以不用书写文件的相对路径,只写出文件名即可。
  (2) 函数名中带有l:表示将新程序的每个命令行参数都当作一个参数传给它,参数个数可变,并且最后要输入一个NULL参数表示参数输入结束。
  (3) 函数名中带有v:表示该类函数支持使用参数数组,数组中的最后一个指针也要输入NULL参数作为结束标志,类似于main()函数的形参argv[].

  (4) 函数名以e结尾:该类函数表示可以将一份新的函数变量表传给它。

示例:execve函数//new2.c#include<stdio.h>#include<unistd.h>#include<sys/types.h>extern char **environ;int main(void){puts("welcome to mrsoft");return 0;}//execve.c#include<stdio.h>#include<unistd.h>#include<sys/types.h>extern char **environ;int main(int argc,char* argv[]){execve("new",argv,environ);//此处调用可执行文件new,也就是new2.c编译后的执行文件//此时进程中的代码段、数据段和进程段都进行了修改,使得新创建的进程只执行新加载的这个程序的代码puts("正常情况下无法输出此信息");}执行结果:welcome to mrsoft!//修改后的execve.c#include<stdio.h>#include<unistd.h>#include<sys/types.h>extern char **environ;int main(int argc,char* argv[]){pid_t pid;if((pid=fork())<0)printf("create child process failed!\n");else if(pid==0)    execve("new",argv,environ);else puts("正常情况下输出此信息!\n");}//运行结果:正常情况下输出此信息!//welcome to mrsoft!//再次修改execve.c//在那个进程中调用,PID还是那个进程的#include<stdio.h>#include<unistd.h>#include<sys/types.h>int gvar=2;//全局变量int main(void){pid_t pid;int var=5;//局部变量printf("process id:%ld\n",(long)getpid());//输出父进程的PIDprintf("gvar=%d var=%d\n",gvar,var);if((pid=fork())<0)//创建子进程失败{perror("error!");return 1;}else if(pid==0)//如果在子进程中执行以下程序{gvar--;var++;//输出子进程的PID和修改后的变量值printf("the child process id:%ld,gvar=%d var=%d\n",(long)getpid(),gvar,var);return 0;}else{   //输出父进程的PID以及变量值printf("the parent process id:%ld,gvar=%d var=%d\n",(long)getpid(),gvar,var);execve("new",argv,environ);return 0;}}//修改后的new.c#include<stdio.h>#include<unistd.h>#include<sys/types.h>extern char **environ;int main(void){puts("welcome to mrsoft");printf("newPID=%ld\n",(long)getpid());return 0;}/*运行结果:process id:4043   gvar=2 var=5   the parent process id:4043,gvar=2,var=5    the child process id:4044,gvar=1,var=6    welcome to mrsoft   newPID=4043*/

3、其他exec函数

#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <errno.h>int main(int argc, char *argv[]){  //以NULL结尾的字符串数组的指针,适合包含v的exec函数参数  char *arg[] = {"ls", "-a", NULL};    /**   * 创建子进程并调用函数execl   * execl 中希望接收以逗号分隔的参数列表,并以NULL指针为结束标志   * 包含有 l ① 说明需要在另加上可执行程序作为第二个参数 当然可以加第三、四个等 待参数   *          ② 注意不能够外加参数,因为它不能添加参数argv,因此不能再加参数   * 不包含l时参数就不用以NULL结尾   */  if( fork() == 0 )  {    // in clild     printf( "1------------execl------------\n" );    if( execl( "/bin/ls", "ls","-a", NULL ) == -1 )    {      perror( "execl error " );      exit(1);    }  }    /**   *创建子进程并调用函数execv,包含v的特点    *execv中希望接收一个以NULL结尾的字符串数组的指针,   *也可以说可以通过外加参数比如:./a -l 等价于 ls -l   */  if( fork() == 0 )  {    // in child     printf("2------------execv------------\n");//注意:execv( "/bin/ls","-l",arg) 是错误的写法,其他参数应另外添加    if( execv( "/bin/ls",arg) < 0)    {      perror("execv error ");      exit(1);    }  }  /**   *创建子进程并调用 execlp   *execlp中与execl类似,多了个p   *l希望接收以逗号分隔的参数列表,列表以NULL指针作为结束标志   *p是一个以NULL结尾的字符串数组指针,函数可以DOS的PATH变量查找子程序文件   */  if( fork() == 0 )  {    printf("3------------execlp------------\n");    if( execlp( "ls", "ls", "-a", NULL ) < 0 )    {      perror( "execlp error " );      exit(1);    }  }    /**   *创建子里程并调用execvp   *v 望接收到一个以NULL结尾的字符串数组的指针   *p 是一个以NULL结尾的字符串数组指针,函数可以DOS的PATH变量查找子程序文件   */  if( fork() == 0 )  {    printf("4------------execvp------------\n");    if( execvp( "ls", arg ) < 0 )    {      perror( "execvp error " );      exit( 1 );    }  }    /**   *创建子进程并调用execle   *l 希望接收以逗号分隔的参数列表,列表以NULL指针作为结束标志   *e 函数传递指定参数envp,允许改变子进程的环境,无后缀e时,子进程使用当前程序的环境   */  if( fork() == 0 )  {    printf("5------------execle------------\n");    if( execle("/bin/ls", "ls", "-a", NULL, NULL) == -1 )    {      perror("execle error ");      exit(1);    }  }    /**   *创建子进程并调用execve   * v 希望接收到一个以NULL结尾的字符串数组的指针   * e 函数传递指定参数envp,允许改变子进程的环境,无后缀e时,子进程使用当前程序的环境   *在运行时另加参数,如:./a -l 如同执行:ls -l    */  if( fork() == 0 )  {    printf("6------------execve-----------\n");    if( execve( "/bin/ls", arg, NULL ) == 0)//必须加上路径,绝对路径或相对路径否则找不到要执行的程序    {      perror("execve error ");      exit(1);    }  }  return EXIT_SUCCESS;}


0 0
原创粉丝点击