首页 > 系统服务 > 详细

第十三章 进程(5)

时间:2019-08-30 00:40:49      阅读:86      评论:0      收藏:0      [点我收藏+]

exec替换进程映像

在进程的创建上Unix采用了一个独特的方法,它将进程创建加载一个新进程映象分离。这样的好处是有更多的余地对两种操作进行管理。
当我们创建了一个进程之后,通常将子进程替换成新的进程映象,这可以用exec系列的函数来进行。当然,exec系列的函数也可以将当前进程替换掉。

?

exec系列函数

头文件<unistd.h>
功能用exec函数可以把当前进程替换为一个新进程。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, char *const argv[]);
     int execvp(const char *file, char *const argv[]);
参数
    * path参数表示你要启动程序的名称包括路径名
    * arg参数表示启动程序所带的参数
    * 带'l'的表示可变参数列表(argument list(仅仅自己理解方便记忆))
    * 带'v'的表示参数是(char* argv[](仅仅自己理解方便记忆))
    * 带‘p'的表示 会从环境变量中搜索是否有这个程序存在
    * 带’e'的表示 会传一个环境信息
返回值:
    * 成功  0
    * 失败  -1

?

代码段、数据段被替换,之后的代码不会被执行

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define ERR_EXIT(m)             do                          {                               perror(m);                  exit(EXIT_FAILURE);     } while (0)


int main(int argc, char *argv[])
{
    printf("Entering main ...\n");
    execlp("ls","ls","-hl",NULL);
    printf("Exiting main ...\n");
    return 0;
}

?
替换进程并不会修改原进程的id

#include <stdio.h>
#include <unistd.h>

int main(void)
{
    printf("pid : %d\n",getpid());
    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define ERR_EXIT(m)             do                          {                               perror(m);                  exit(EXIT_FAILURE);     } while (0)


int main(int argc, char *argv[])
{
    printf("Entering main ...\n");
    printf("before replace pid : %d\n",getpid());
    //代码段、数据段被替换
    //int ret = execlp("./hello","hello",NULL);

    //linux默认情况下是在环境变量(echo $PATH)下搜索源程序
    int ret = execlp("hello","hello",NULL);
    if(ret == -1)
        perror("execlp error");
    printf("Exiting main ...\n");
    return 0;
}

?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define ERR_EXIT(m)             do                          {                               perror(m);                  exit(EXIT_FAILURE);     } while (0)


int main(int argc, char *argv[])
{
    char* const args[] = {"ls","-l",NULL};
    printf("Entering main ...\n");

    "第一个参数可以是绝对路径,也可以是相对路径,也可以不带路径"
    //int ret = execlp("ls","ls","-l",NULL);
    int ret = execvp("ls",args);
    if(ret == -1)
        perror("execlp error");

    printf("Exiting main ...\n");
    return 0;
}

?
例子1

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define ERR_EXIT(m)             do                          {                               perror(m);                  exit(EXIT_FAILURE);     } while (0)


int main(int argc, char *argv[])
{
    printf("Entering main ...\n");

    //带'p'的表示会从环境变量或指定的路径获取文件
    //execlp("ls","ls","-hl",NULL);

    char *const args[] = {"ls", "-hl", NULL};
    //execvp("ls", args);

    // 并不会在环境变量中搜索,这个地方必须给出一个路径(相对路径和绝对路径都可以)
    //int ret = execv("ls", args);
    //int ret = execl("ls","ls","-hl",NULL);
    if( ret < 0 )
    {
        perror("execl");
    }

    printf("Exiting main ...\n");
    return 0;
}

?
例子2

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define ERR_EXIT(m)             do                          {                               perror(m);                  exit(EXIT_FAILURE);     } while (0)


int main(int argc, char *argv[])
{
    printf("Entering main ...\n");

    //execl执行hello,会将当前的环境信息传递给hello,
    //而当前进程的环境信息,是从shell中继承下来的

    //简单的说,就是执行“execl”这个程序的的时候,shell会被做为参数,传递到进程中,
    //在进程中又调用execl,执行"hello"这个程序,“execl”又将shell作为参数传递到“hello"这个进程中
    /* int ret = execl("./hello", "hello", NULL);
    if(ret == -1)
    {
        perror("execl");
    } */

    //设置自己的环境变量信息
    char* const envp[] = {"AA=1", "BB=2", NULL};
    int ret = execle("./hello", "hello", NULL, envp);
    if(ret == -1)
    {
        perror("execl");
    }

    printf("Exiting main ...\n");
    return 0;
}

技术分享图片

?
例子3

#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>

//全部变量,C库中已存在,此处声明下就可以
extern char** environ;

int main(int argc, char const *argv[])
{
   printf("hello! pid = %d\n",getpid());
   int i;
   for(i=0; environ[i] != NULL; ++i)
   {
      printf("%s\n",environ[i]);
   }

   return 0;
}


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

#define ERR_EXIT(m)             do                          {                               perror(m);                  exit(EXIT_FAILURE);     } while (0)


int main(int argc, char *argv[])
{
    printf("Entering main ...\n");

    /*
    man 2 fcntl;
    File descriptor flags
       The following commands manipulate the flags associated with a file descriptor.  Currently, only one such flag
       is defined: FD_CLOEXEC, the close-on-exec flag.  If the FD_CLOEXEC bit is 0, the file descriptor will  remain
       open across an execve(2), otherwise it will be closed.
    */
   //如果将一个文件描述符设置为FD_CLOEXEC,当我们调用execve进行替换的时候,文件描述符会被关闭 

    int ret = fcntl(1, F_SETFD, FD_CLOEXEC);//置1
    if(ret == -1)
    {
        perror("fcntl");
    }

    //execlp替换成功,但是因为设置了FD_CLOEXEC,调用hello的时候,1号文件描述符被关闭了,所以”hello"程序无法输出
    //对于open()函数,在打开文件的时候,我们可以加O_CLOEXEC,表示将FD_CLOEXEC置为1,当调用exec系列会自动关闭文件描述符
    ret = execlp("./hello", "hello", NULL);
    if(ret == -1)
    {
        perror("execl");
    }

    printf("Exiting main ...\n");
    return 0;
}

第十三章 进程(5)

原文:https://www.cnblogs.com/s3320/p/11397380.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!