创建新进程

创建新进程:
与fork()不同,exec函数不是创建调用进程的子进程,而是创建一个新的进程
取代调用进程自身,新进程会用自己的全部地址空间,覆盖调用进程的空间,
但进程的PID保持不变
int execl(const char*path,const char *arg,...);
功能:创建新进程,PID不变
参数: path:可执行文件的路径
           arg:命令行参数内容
execl("./a.out","a.out","123","hello",NULL);//命令行参数以空结束
函数成功不返回,失败返回-1.

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[]);

file:文件名 //传文件名会通过环境变量表找文件
argv[]:命令行参数指针数组//以NULL结尾
envp[]:环境变量指针数组//以NULL结尾

调用exec函数不仅改变调用进程的地址空间和进程映像,调用进程的一些
属性也发生了变化。
1、任何处于阻塞状态的信号都会消失
2、被设置为捕获的信号会还原为默认操作
3、有关线程属性的设置会还原为缺省值
4、有关进程的统计信息会复位
5、与进程内存相关的任何数据都会丢失,包括内存映射文件
6、标准库在用户空间维护的一切数据结构(如通过atexit或on_exit函数注册的
退出函数)都会丢失
但有些属性会被进程继承下来,比如PID,PPID,实际用户ID和实际组ID、优先级,
以及文件描述符等。
注意如果进程创建成功,exec函数是不会返回的,因为成功的exec调用会以跳转
到新进程的入口地址作为结束,而刚刚运行的代码是不会存在于新进程的地址空
间中的,但如果进程创建失败,exec函数会返回-1.

调用exec函数固然可以创建出新的进程,但是新进程会取代原来的进程。如果既想
创建新进程,同时又希望原来的进程继续存在,则可以考虑fork+exec模式,即在
fork产生的子进程里调用exec函数,新进程取代了子进程,但父进程依然存在。
 

//新进程的创建exec.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

int main()
{
    printf("当前进程:%d\n",getpid());
    /*if(execl("../day11/waitpid","waitpid",NULL) ==-1)
    {
        perror("execl");
        return -1;
    }*/
    /*
    if(execlp("ls","ls","-la",NULL)== -1)
    {
        perror("execl");
        return -1;
    }*/
    char *envp[] = {"FOOD=GUOBAOROU","AGE=18","NAME=lli",NULL};
    if(execle("./new","new","123","hello",NULL,envp) ==-1)
    {
        perror("execle");
        return -1;
    }
    printf("变身结束的进程:%d\n",getpid());
    return 0;
}
//execl
当前进程:92219
父进程:92219
子进程:92220
子进程:92221
子进程:92222
子进程:92223
我是92219父进程,我要回收92224子进程
子进程:92224
92219父进程回收92224子进程
我是92219父进程,我要回收92223子进程
92219父进程回收92223子进程
我是92219父进程,我要回收92222子进程
92219父进程回收92222子进程
我是92219父进程,我要回收92221子进程
92219父进程回收92221子进程
我是92219父进程,我要回收92220子进程
92219父进程回收92220子进程
//execlp
当前进程:92264
总用量 36
drwxrwxr-x  2 tarena tarena  4096 6月   1 11:14 .
drwxrwxr-x 14 tarena tarena  4096 6月   1 10:43 ..
-rwxrwxr-x  1 tarena tarena  8760 6月   1 11:14 execl
-rw-rw-r--  1 tarena tarena   412 6月   1 11:11 execl.c
-rw-------  1 tarena tarena 12288 6月   1 11:11 .execl.c.swp

//execle
当前进程:92373
PID:92373
命令行参数
new
123
hello
环境变量
FOOD=GUOBAOROU
AGE=18
NAME=ll
//new.c
#include<stdio.h>
#include<unistd.h>

int main(int argc,char *argv[],char *envp[])
{
    printf("PID:%d\n",getpid());
    printf("命令行参数\n");
    for(char **pp = argv;*pp;pp++)
    {
        printf("%s\n",*pp);
    }
    printf("环境变量\n");
    for(char **pp = envp;*pp;pp++)
    {
        printf("%s\n",*pp);
    }
    return 0;
}
//fork+exec
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>

int main(void)
{
    printf("父进程:%d\n",getpid());
    //创建子进程,让子进程变成ls
    pid_t pid1 =fork();
    if(pid1 == -1)
    {
        perror("fork");
        return -1;
    }
    if(pid1 == 0)
    {
        if(execl("/bin/ls","ls","-i","-l","-a",NULL) == -1)
        {
            perror("execl");
            return -1;
        }
        //return 0;//取代成功之后,后面语句不会执行,失败走if不执行
    }
    //父进程负责回收子进程僵尸
    int status;//输出子进程的终止状态
    if(waitpid(-1,&status,0) == -1)
    {
        perror("waitpid");
        return -1;
    }
    if(WIFEXITED(status))
    {
        printf("正常终止,退出码%d\n",WEXITSTATUS(status));
    }
    else
    {
        printf("异常终止,信号%d",WTERMSIG(status));
    }
    //再创建子进程,变身new
    pid_t pid2 = fork();
    if(pid2 == -1)
    {
        perror("fork");
        return 0;
    }
    if(pid2 == 0)
    {
        if(execl("./new","new","123",NULL) == -1)
        {
            perror("execl");
            return -1;
        }
    }
    
    if(waitpid(-1,&status,0) == -1)
    {
        perror("waitpid");
        return -1;
    }
    if(WIFEXITED(status))
    {
        printf("正常终止,退出码%d\n",WEXITSTATUS(status));
    }
    else
    {
        printf("异常终止,信号%d",WTERMSIG(status));
    }
    return 0;
}


父进程:92729
总用量 68
2896362 drwxrwxr-x  2 tarena tarena  4096 6月   1 12:57 .
1853125 drwxrwxr-x 14 tarena tarena  4096 6月   1 10:43 ..
2905886 -rwxrwxr-x  1 tarena tarena  8824 6月   1 11:38 execl
2905890 -rw-rw-r--  1 tarena tarena   601 6月   1 12:21 execl.c
2905889 -rw-rw-r--  1 tarena tarena  1483 6月   1 12:57 forf_exec.c
2905883 -rw-------  1 tarena tarena 12288 6月   1 12:57 .forf_exec.c.swp
2905887 -rwxrwxr-x  1 tarena tarena  8928 6月   1 12:57 fork_exec
2905888 -rwxrwxr-x  1 tarena tarena  8704 6月   1 12:52 new
2905893 -rw-rw-r--  1 tarena tarena   347 6月   1 12:52 new.c
正常终止,退出码0
PID:92731
命令行参数
new
123
环境变量
XDG_VTNR=7
LC_PAPER=zh_CN.UTF-8
LC_ADDRESS=zh_CN.UTF-8
XDG_SESSION_ID=c2
XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/tarena
LC_MONETARY=zh_CN.UTF-8
CLUTTER_IM_MODULE=ibus
SESSION=ubuntu
GPG_AGENT_INFO=/home/tarena/.gnupg/S.g

#include<stdlib.h>
int system(const char* command);
功能:执行shell命令
参数:command shell命令行字符串
返回值:成功返回command进程的终止状态,失败返回-1
system函数执行command参数所表示的命令行,并返回命令进程的终止状态
若command参数取NULL,返回非0表示shell可用,返回0表示shell不可用

在system函数内部调用vfork、exec和waitpid等函数
如果调用vfork或waitpid函数出错,则返回-1
如果调用exec函数出错,则在子进程中执行exit(127)
如果都成功,则返回command进程的终止状态(由waitpid的status参数获得)

使用system函数而不用vfork+exec的好处是,system函数针对各种错误和
信号都做了必要的处理,而且system是标准库函数,可跨平台使用
 

//使用system
#include<stdio.h>
#include<stdlib.h>

int main()
{
    int status = system("ls -a");
    if(status == -1)
    {
        perror("system");
        return -1;
    }
    if(WIFSIGNALED(status))
    {
        printf("异常终止:%d",WTERMSIG(status));
    }
    else
    {
        printf("正常终止:%d",WEXITSTATUS(status));
    }
    
    status = system("./new 123 hello");
    if(status == -1)
    {
        perror("system");
        return -1;
    }
    if(WIFSIGNALED(status))
    {
        printf("异常终止:%d",WTERMSIG(status));
    }
    else
    {
        printf("正常终止:%d",WEXITSTATUS(status));
    }

    return 0;
}


.  ..  execl  execl.c  forf_exec.c  fork_exec  new  new.c  system  system.c  .system.c.swp
PID:92850
命令行参数
./new
123
hello
环境变量
LIBRARY_PATH=:.:..:.
LESSOPEN=| /usr/bin/lesspipe %s
C_INCLUDE_PATH=:.:../include:.:../include
GNOME_KEYRING_PID=
MAIL=/var/mail/tarena

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值