当前位置 : 主页 > 网络编程 > net编程 >

[ Linux ] 进程控制(下)----进程等待与进程程序替换

来源:互联网 收集:自由互联 发布时间:2023-09-06
文章目录 ​​前言​​ ​​一、进程等待​​ ​​1.1 进程等待必要性​​ ​​1.2 进程等待的方法​​ ​​wait方法​​ ​​wait_pid()​​ ​​退出码和信号码​​ ​​阻塞等待和非


文章目录

  • ​​前言​​
  • ​​一、进程等待​​
  • ​​1.1 进程等待必要性​​
  • ​​1.2 进程等待的方法​​
  • ​​wait方法​​
  • ​​wait_pid()​​
  • ​​退出码和信号码​​
  • ​​阻塞等待和非阻塞等待​​
  • ​​非阻塞的理解​​
  • ​​二、进程程序替换​​
  • ​​2.1 进程程序替换是什么​​
  • ​​2.1.1 概念​​
  • ​​2.1.2 原理​​
  • ​​2.2 为什么要进行程序替换​​
  • ​​2.3 如何进行程序替换​​
  • ​​使用接口​​
  • ​​execl​​
  • ​​引入进程创建​​
  • ​​execv​​
  • ​​execlp​​
  • ​​execvp​​
  • ​​execle​​

前言

本小节继续承接上文​​进程控制​​继续对进程控制中的进程等待和进程程序替换内容进行讲解!


​正文开始​

一、进程等待

1.1 进程等待必要性

  • 之前在​​进程状态​​这篇博客中我们讲到:子进程退出,父进程如果不管不顾,就可能造成"僵尸进程"的问题,进而造成内存的泄漏!
  • 另外,进程一旦进程变成僵尸状态,那就刀枪不入,"杀人不眨眼"得kill -9也无能为力,因为谁也没有办法杀死一个已经死去的进程。
  • 最后,父进程派给子进程的任务完成的如何,我们需要知道。如:子进程运行完成,结果对还是不对,或者是否正常退出。( 获取子进程的退出状态!,因为进程退出是有退出码的。)
  • 父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息。

1.2 进程等待的方法

wait方法

系统给我们提供了wait接口方法,wait()的方案可以解决挥手子进程Z状态,让子进程进入X状态。

[ Linux ] 进程控制(下)----进程等待与进程程序替换_服务器

#include<stdio.h>
2 #include<unistd.h>
3 #include<string.h>
4 #include<stdlib.h>
5 #include<sys/wait.h>
6 #include<sys/types.h>
7
8
9 int main()
10 {
11 pid_t id=fork();
12 if(id==0)
13 {
14 //child
15 while(1)
16 {
17 printf("我是子进程,我正在运行...pid:%d\n",getpid());
18 sleep(1);
19 }
20 }
21 else
22 {
23 printf("我是父进程,pid:%d,我准备等待子进程啦!!!\n",getpid());
24 sleep(30);
25 pid_t ret=wait(NULL);
26 if(ret<0)
27 {
28 printf("等待失败!\n");
29 }
30 else
31 {
32 printf("等待成功!result:%d\n",ret);
33 }
34 sleep(20);
35 }
36 return 0;
37 }

运行我们的程序

[ Linux ] 进程控制(下)----进程等待与进程程序替换_服务器_02

在我们另一侧执行

kill -0 子进程pid

子进程就会进入僵尸状态(Z状态)

[ Linux ] 进程控制(下)----进程等待与进程程序替换_#include_03


然后打开我们的监控脚本查看子进程的退出状态变化!

while :; do ps ajx |head -1 && ps ajx |grep myproc |grep -v grep; echo “####################”; sleep 1;done

"#"是作为一个区分符,方便我们查看进程状态

[ Linux ] 进程控制(下)----进程等待与进程程序替换_服务器_04

[ Linux ] 进程控制(下)----进程等待与进程程序替换_子进程_05


父进程等待成功后,返回子进程的pid。

[ Linux ] 进程控制(下)----进程等待与进程程序替换_#include_06


最后程序结束,父进程也就退出了。

wait_pid()

我们首先与wait进行比较,wait是等待任意一个退出的子进程!

今天我们的重点是关于wait_pid()的讲解!

[ Linux ] 进程控制(下)----进程等待与进程程序替换_子进程_07


pid_t:(返回值)

  • >0:等待子进程成功,返回值就是子进程的pid
  • <0:等待失败

waitpid的第一个参数pid

  • >0:是几,就代表等待哪一个子进程。
  • -1:等待任意进程

waitpid的第二个参数status

  • 这个参数,是一个输出型参数(通过调用这个函数,我要得到什么信息或者数据)
  • 进程退出,如果异常退出,是因为这个进程收到了特定的信号!!–>获取退出信号
  • 等等之后了解。

    带大家看看内核数据结构里面的描述!

    对于int* status
    今天我们只需要关心整数低16个比特位

8-15个比特位代表程序的退出状态
0-7比特位代表程序推出的信号

waitpid的第三个参数options

  • 现在我们先来第一个选项为0是进行阻塞等待。

下来我们进行验证!

1 #include<stdio.h>
2 #include<unistd.h>
3 #include<string.h>
4 #include<stdlib.h>
5 #include<sys/wait.h>
6 #include<sys/types.h>
7
8
9 int main()
10 {
11 pid_t id=fork();
12 if(id==0)
13 {
14 //child
15 int cnt=5;
16 while(1)
17 {
18 printf("我是子进程,我正在运行...pid:%d\n",getpid());
19 sleep(1);
20 cnt--;
21 if(cnt==0)
22 {
23 break;
24 }
25 }
26 exit(13);
}
28 else
29 {
30 printf("我是父进程,pid:%d,我准备等待子进程啦!!!\n",getpid());
31 int status=0;
32 pid_t ret=waitpid(id,&status,0);
33 if(ret>0)
34 {
35 printf("wait success, ret:%d,我所等待的子进程的退出码:%d\n",ret,(status>>8)&0xFF);
36 }
37 }
38}

子进程的退出码为13,那么我们能如愿得到子进程的退出码吗?

下来我们看结果!!!

[ Linux ] 进程控制(下)----进程等待与进程程序替换_服务器_08


我们如愿得到了结果:子进程的退出码!

下来我们验证关于status的低七位的含义

1 #include<stdio.h>
2 #include<unistd.h>
3 #include<string.h>
4 #include<stdlib.h>
5 #include<sys/wait.h>
6 #include<sys/types.h>
7
8
9 int main()
10 {
11 pid_t id=fork();
12 if(id==0)
13 {
14 //child
16 while(1)
17 {
18 printf("我是子进程,我正在运行...pid:%d\n",getpid());
19 sleep(1);
25 }
26 exit(0);
27 }
28 else
29 {
30 printf("我是父进程,pid:%d,我准备等待子进程啦!!!\n",getpid());
31 int status=0;
32 pid_t ret=waitpid(id,&status,0);
33 if(ret>0)
34 {
35 printf("wait success, ret:%d,我所等待的子进程的退出码:%d,退出信号是:%d\n",ret,(status>>8)&0xFF,(status)&0x7F);
36 }
37
38 }
39 }
40

[ Linux ] 进程控制(下)----进程等待与进程程序替换_#include_09


我们使用kill -9 杀掉子进程后,果然得到了子进程的异常信号。

[ Linux ] 进程控制(下)----进程等待与进程程序替换_运维_10


不同的异常退出会得到不同的信号!

下来看看Linux下的退出信号有哪些

kill -l

[ Linux ] 进程控制(下)----进程等待与进程程序替换_服务器_11


我们可以看到没有0号退出信号!!!

接下来再带大家看看除0错误,这个系统会自动退出,不需要我们杀掉他!

1 #include<stdio.h>
2 #include<unistd.h>
3 #include<string.h>
4 #include<stdlib.h>
5 #include<sys/wait.h>
6 #include<sys/types.h>
7
8
9 int main()
10 {
11 pid_t id=fork();
12 if(id==0)
13 {
14 //child
16 while(1)
17 {
18 printf("我是子进程,我正在运行...pid:%d\n",getpid());
19 sleep(10);
int a=10/0;
25 }
26 exit(0);
27 }
28 else
29 {
30 printf("我是父进程,pid:%d,我准备等待子进程啦!!!\n",getpid());
31 int status=0;
32 pid_t ret=waitpid(id,&status,0);
33 if(ret>0)
34 {
35 printf("wait success, ret:%d,我所等待的子进程的退出码:%d,退出信号是:%d\n",ret,(status>>8)&0xFF,(status)&0x7F);
36 }
37
38 }
39 }
40

[ Linux ] 进程控制(下)----进程等待与进程程序替换_子进程_12


还有空引用等等错误,也会导致程序异常终止,返回信号码给父进程。

注意:wait()/waitpid()是系统调用接口!

退出码和信号码

关于退出码和信号码,那么先看那个呢?—>信号码!

一旦进程出现异常退出后,只关心退出信号,退出码没有任何意义!

status:
WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)

#include<stdio.h>
2 #include<unistd.h>
3 #include<string.h>
4 #include<stdlib.h>
5 #include<sys/wait.h>
6 #include<sys/types.h>
7
8
9 int main()
10 {
11 pid_t id=fork();
12 if(id==0)
13 {
14 //child
15 //int cnt=5;
16 while(1)
17 {
18 printf("我是子进程,我正在运行...pid:%d\n",getpid());
19 sleep(10);
20 break;
27 }
28 exit(10);
29 }
30 else
31 {
32 printf("我是父进程,pid:%d,我准备等待子进程啦!!!\n",getpid());
33 int status=0;
34 pid_t ret=waitpid(id,&status,0);
35 if(ret>0)
36 {
37 if(WIFEXITED(status))
38 {
39 printf("子进程是正常退出的,退出码:%d\n",WEXITSTATUS(status));
40 }
43 }
44}

[ Linux ] 进程控制(下)----进程等待与进程程序替换_服务器_13

阻塞等待和非阻塞等待

当我们调用某些函数的时候,因为条件不就绪,需要我们阻塞等待。
本质:就是当前进程自己变成阻塞状态,等待条件就绪的时候,在被唤醒!

非阻塞的理解

对于waitpid()的最后一个参数options
0:标识阻塞等待。

在子进程休眠的时候,父进程在此期间可以去做别的事情。
多次调用非阻塞接口—轮询检测!

options:
WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID。

下来带大家看看waitpid的返回值

[ Linux ] 进程控制(下)----进程等待与进程程序替换_运维_14


修改父进程中的代码即可!

//基于非阻塞的轮询等待方案
33 int status=0;
34 while(1)
35 {
36 pid_t ret=waitpid(-1,&status,WNOHANG);
37 if(ret>0)
38 {
39 printf("子进程是正常退出的,退出码:%d\n",WEXITSTATUS(status));
40 break;
41 }
42 else if(ret==0)
43 {
44 //等待成功了,但是子进程没有退出
45 printf("子进程还没好,那我父进程在做其他事情...\n");
46 sleep(1);
47 }
48 else
49 {
50 //出错了,暂时不处理
51
52 }

[ Linux ] 进程控制(下)----进程等待与进程程序替换_子进程_15

二、进程程序替换

2.1 进程程序替换是什么

2.1.1 概念

通过之前的学习,我们知道子进程执行的是父进程的代码片段。

如果我们想让创建出来的子进程,执行的是全新的程序呢?

这里我们就需要用到进程程序替换。

2.1.2 原理

1.将磁盘中的程序,加载入内存结构

2.重新建立页表映射,谁执行程序替换,就重新建立谁的映射(子进程)
效果:让我们的父进程和子进程彻底分离,并让子进程执行一个新的程序。

[ Linux ] 进程控制(下)----进程等待与进程程序替换_linux_16


那么问题来了!!!

这个过程有没有创建新的进程呢?

答:我们肯定没有创建新的进程,只不过让子进程执行了新的程序。

2.2 为什么要进行程序替换

我们一般在服务器设计(linux编程)的时候,往往需要子进程干两件种类的事情

  1. 让子进程执行父进程的代码片段(服务器代码)
  2. 让子进程执行磁盘中的一个全新的程序(shell,想让客户端执行对应的程序,通过我们的进程,执行其他人写的进程的代码等等)

例如我们用C语言的进程去掉java/python/C++等等的程序。

2.3 如何进行程序替换

由OS完成,所以我们要调用系统接口。

首先带大家来看看系统接口有什么!

[ Linux ] 进程控制(下)----进程等待与进程程序替换_运维_17

我们如果要执行一个全新的程序,我们需要做几件事情呢?

  1. 程序本质就是一个磁盘上的文件,所以我们需要先找到这个程序在哪里
  2. 程序可能携带选项进行执行(也可以不携带),然后告诉OS,我要怎么执行这个程序?(要不要带选项)

使用接口

execl

[ Linux ] 进程控制(下)----进程等待与进程程序替换_#include_18


其中参数列表中:“…” 叫做可变参数,说白了就是可以按照用户的意愿传入参数的大小个数,如果还不理解,大家肯定都用过C语言中的printf函数吧,printf有没有规定你只能打印几个参数呢?没有的,这是根据用户自己来定义的!这就是可变参数

1 #include<stdio.h>
2 #include<unistd.h>
3 #include<sys/wait.h>
4 #include<stdlib.h>
5
6 int main()
7 {
8 printf("我是一个进程,我的pid是:%d\n",getpid());
9 execl("/usr/bin/ls","ls","-l","-a",NULL);
10 printf("我执行完毕了,我的pid是:%d\n",getpid());
15 return 0;
16 }

[ Linux ] 进程控制(下)----进程等待与进程程序替换_运维_19

执行top命令

1 #include<stdio.h>
2 #include<unistd.h>
3 #include<sys/wait.h>
4 #include<stdlib.h>
5
6 int main()
7 {
8 printf("我是一个进程,我的pid是:%d\n",getpid());
9 //execl("/usr/bin/ls","ls","-l","-a",NULL);
10 execl("/usr/bin/top","top",NULL);
11 printf("我执行完毕了,我的pid是:%d\n",getpid());
16 return 0;
17 }

[ Linux ] 进程控制(下)----进程等待与进程程序替换_运维_20


执行完以上的代码,我们发现一个问题!!!

最后一句代码为什么没有被打印出来呢!!!

[ Linux ] 进程控制(下)----进程等待与进程程序替换_运维_21


因为进程一旦替换成功,是将当前进程的代码和数据全部替换了!!!

后面的printf是代码吗??有没有被替换呢??当然,已经早就被替换了!!改代码不存在了!!

所以这个程序替换函数,用不用判断返回值?为什么?

答:不用判断返回值,因为只要成功了,就不会有返回值。而失败的时候,必然会继续向后执行!!最多通过返回值得到什么原因导致的替换失败!

引入进程创建

6 int main()          
7 {
8 printf("我是一个进程,我的pid是:%d\n",getpid());
9 pid_t id=fork();
10 if(id==0)
11 {
12 //child
13 //我们想让子进程执行新的程序,以前是执行父进程的代码片段
14 printf("我是子进程,我的pid是:%d\n",getpid());
15 execl("/usr/bin/ls","ls","-l","-a",NULL);
16
17 exit(1);
18 }
19 //一定是父进程
20 int status=0;
21 int ret=waitpid(id,&status,0);
22 if(ret==id)
23 {
24 sleep(2);
25 printf("父进程等待成功!\n");
26 }
27
28 return 0;
29 }

[ Linux ] 进程控制(下)----进程等待与进程程序替换_#include_22


子进程进行程序替换的时候会不会影响父进程呢?

答:不会,因为进程具有独立性。

为什么?如何做到的?

因为数据层面发生了写时拷贝!当程序替换的时候,我们可以理解成为,代码和数据都发生了写时拷贝,完成了父子的分离。

execv

[ Linux ] 进程控制(下)----进程等待与进程程序替换_运维_23


他的第二个参数是一个指针数组,他和execl的区别就是把选项作为参数放入指针数组,然后进行传参!

int main()
7 {
8 printf("我是一个进程,我的pid是:%d\n",getpid());
9 pid_t id=fork();
10 if(id==0)
11 {
12 //child
13 //我们想让子进程执行新的程序,以前是执行父进程的代码片段
14 printf("我是子进程,我的pid是:%d\n",getpid());
15 char *const argv_[]={
16 (char*)"ls",
17 (char*)"-a",
18 (char*)"-l",
19 NULL
20 };
21 execv("/usr/bin/ls",argv_);
22 exit(1);
23 }
24 //一定是父进程
25 int status=0;
26 int ret=waitpid(id,&status,0);
27 if(ret==id)
28 {
29 sleep(2);
30 printf("父进程等待成功!\n");
31 }
32
33 return 0;
34 }

[ Linux ] 进程控制(下)----进程等待与进程程序替换_服务器_24


区分execl和execv

[ Linux ] 进程控制(下)----进程等待与进程程序替换_#include_25

execlp

[ Linux ] 进程控制(下)----进程等待与进程程序替换_#include_26


相比于execl这个接口的第一个参数变化。

我们执行指令的时候,默认的搜索路径,在哪里搜索呢?
环境变量PATH!

p代表PATH

所以命名中带p的,可以不带路径,只要说出你要执行哪一个程序即可!

#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>

int main()
{
printf("我是一个进程,我的pid是:%d\n",getpid());
pid_t id=fork();
if(id==0)
{
//child
//我们想让子进程执行新的程序,以前是执行父进程的代码片段
printf("我是子进程,我的pid是:%d\n",getpid());
char *const argv_[]={
(char*)"ls",
(char*)"-a",
(char*)"-l",
NULL
};
execlp("ls","ls","-a","-l",NULL);//这里出现了两个ls,含义一样吗?不一样!
exit(1);
}
//一定是父进程
int status=0;
int ret=waitpid(id,&status,0);
if(ret==id)
{
sleep(2);
printf("父进程等待成功!\n");
}

return 0;
}

[ Linux ] 进程控制(下)----进程等待与进程程序替换_服务器_27


照样也是可以执行的!

execvp

[ Linux ] 进程控制(下)----进程等待与进程程序替换_子进程_28


和前面的知识我们结合起来就了解了这个接口的参数!

#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>

int main()
{
printf("我是一个进程,我的pid是:%d\n",getpid());
pid_t id=fork();
if(id==0)
{
//child
//我们想让子进程执行新的程序,以前是执行父进程的代码片段
printf("我是子进程,我的pid是:%d\n",getpid());
char *const argv_[]={
(char*)"ls",
(char*)"-a",
(char*)"-l",
NULL
};
execvp("ls",argv_);
exit(1);
}
//一定是父进程
int status=0;
int ret=waitpid(id,&status,0);
if(ret==id)
{
sleep(2);
printf("父进程等待成功!\n");
}

return 0;
}

[ Linux ] 进程控制(下)----进程等待与进程程序替换_#include_29

execle

[ Linux ] 进程控制(下)----进程等待与进程程序替换_#include_30


这里的前两个接口都非常熟悉了,这里最后一个接口叫做环境变量。那么为什么要有这个接口呢?

说到环境变量之前我们先来看一下这个问题,我们刚刚提到过,进程替换可以让我们执行其他语言写的程序,那么我们怎么来执行呢?(我们使用execl 函数来调用)

我们现在的目标是想用我们写的myexec.c把mycmd.cpp调用起来,那么怎么来用呢?
myexec.c

#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>

int main()
{
printf("我是一个进程,我的pid是:%d\n",getpid());
pid_t id=fork();
if(id==0)
{
//child
printf("我是子进程,我的pid是:%d\n",getpid());
execl("/home/hulu/lesson10/mycmd","./mycmd",NULL);
exit(1);
}
//一定是父进程
int status=0;
int ret=waitpid(id,&status,0);
if(ret==id)
{
sleep(2);
printf("父进程等待成功!\n");
}

return 0;
}

mycmd.cpp

#include<iostream>
#include<stdlib.h>
int main()
{
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
return 0;
}

[ Linux ] 进程控制(下)----进程等待与进程程序替换_linux_31


我们当前使用的是绝对路径来吊用我的mycmd程序!

当然我们也可以使用相对路径来调用。

相对路径调用

#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>

int main()
{
printf("我是一个进程,我的pid是:%d\n",getpid());
pid_t id=fork();
if(id==0)
{
//child
printf("我是子进程,我的pid是:%d\n",getpid());
execl("./mycmd","mycmd",NULL);
exit(1);
}
//一定是父进程
int status=0;
int ret=waitpid(id,&status,0);
if(ret==id)
{
sleep(2);
printf("父进程等待成功!\n");
}

return 0;
}

[ Linux ] 进程控制(下)----进程等待与进程程序替换_子进程_32


我们再运行发现,仍然是可以成功的。当然也可以用我们的程序来调用python语言,shell脚本语言等等。

程序替换调用python的程序

#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>

int main()
{
printf("我是一个进程,我的pid是:%d\n",getpid());
pid_t id=fork();
if(id==0)
{
//child
printf("我是子进程,我的pid是:%d\n",getpid());
execl("/usr/bin/python3","python3","test.py",NULL);
exit(1);
}
//一定是父进程
int status=0;
int ret=waitpid(id,&status,0);
if(ret==id)
{
sleep(2);
printf("父进程等待成功!\n");
}

return 0;
}
1 #!/usr/bin/python3                                                              
2
3 print("hello python!");
4 print("hello python!");
5 print("hello python!");
6 print("hello python!");
7 print("hello python!");
8 print("hello python!");
9 print("hello python!");

[ Linux ] 进程控制(下)----进程等待与进程程序替换_服务器_33


程序替换调用shell的程序

#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>

int main()
{
printf("我是一个进程,我的pid是:%d\n",getpid());
pid_t id=fork();
if(id==0)
{
//child
printf("我是子进程,我的pid是:%d\n",getpid());
execl("/usr/bin/bash","bash","test.sh",NULL);
exit(1);
}
//一定是父进程
int status=0;
int ret=waitpid(id,&status,0);
if(ret==id)
{
sleep(2);
printf("父进程等待成功!\n");
}

return 0;
}
#!/usr/bin/bash 

cnt=0;

while [ $cnt -le 10 ]
do
echo "hello shell!"
let cnt++
done

[ Linux ] 进程控制(下)----进程等待与进程程序替换_服务器_34


[ Linux ] 进程控制(下)----进程等待与进程程序替换_#include_35


所以我们使用ece系列的系统级函数可以把任何语言耦合在一起!谈完这个话题我们再来谈谈环境变量,execle这个函数多了一个e,这个e就是环境变量,如果你想给这个函数传入环境变量,我们就可以传入环境变量。

[ Linux ] 进程控制(下)----进程等待与进程程序替换_子进程_36

首先我们先来传入一个系统存在的环境变量,然后让我们使用myexec.c程序去调用这个函数

#include<iostream>
#include<stdlib.h>
int main()
{

std::cout<<"PATH:"<<getenv("PATH")<<std::endl;
std::cout<<"-----------------"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
return 0;
}

[ Linux ] 进程控制(下)----进程等待与进程程序替换_服务器_37

发现没有任何问题,那么如果我们想 传入一个自己手动写的环境变量呢?

#include<iostream>
#include<stdlib.h>
int main()
{

std::cout<<"PATH:"<<getenv("PATH")<<std::endl;
std::cout<<"-----------------"<<std::endl;
std::cout<<"MYPATH"<<getenv("MYPATH")<<std::endl;
std::cout<<"--------------"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;


return 0;
}

[ Linux ] 进程控制(下)----进程等待与进程程序替换_子进程_38


运行到这里我们可以发现mycmd.cpp中下面的代码没有打出来,很显然是程序崩溃了!!!这是因为环境变量"MYPATH"在系统中是不存在的,用函数获取,获取失败了,直接就退出进程!

[ Linux ] 进程控制(下)----进程等待与进程程序替换_服务器_39


那么我想让我调用这个进程手动传入环境变量呢?这里我们可以调用系统接口execle,相比于execl多了一个e,这个e就代表的是环境变量!

#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>

int main()
{
printf("我是一个进程,我的pid是:%d\n",getpid());
pid_t id=fork();
if(id==0)
{
//child
printf("我是子进程,我的pid是:%d\n",getpid());
char*const env_[]={
(char*)"MYPATH=YOU Can See Me!\n",
NULL
};

execle("./mycmd","mycmd",NULL,env_);
}
//一定是父进程
int status=0;
int ret=waitpid(id,&status,0);
if(ret==id)
{
sleep(2);
printf("父进程等待成功!\n");
}

return 0;
}

[ Linux ] 进程控制(下)----进程等待与进程程序替换_#include_40


但是运行后,我们还是可以发现这个进程崩溃了,还是没有打印出代码!

接下来我们屏蔽一些代码

#include<iostream>
#include<stdlib.h>
int main()
{

//std::cout<<"PATH:"<<getenv("PATH")<<std::endl;
std::cout<<"-----------------"<<std::endl;
std::cout<<"MYPATH"<<getenv("MYPATH")<<std::endl;
std::cout<<"--------------"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;
std::cout<<"hello C++"<<std::endl;


return 0;
}

[ Linux ] 进程控制(下)----进程等待与进程程序替换_运维_41


这里我们发现我们导入的环境变量出现了!

我们很好奇为什么呢?依照上面两个实验我们可以得出什么结论呢?

我们可以得出execle添加环境变量给目标程序的时候是覆盖式传入的!!!

我们自己传入系统的环境变量给我们程序替换的程序

#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>

int main()
{
//环境变量的指针声明
extern char** environ;

printf("我是一个进程,我的pid是:%d\n",getpid());
pid_t id=fork();
if(id==0)
{
//child
printf("我是子进程,我的pid是:%d\n",getpid());
char* const env_[]={
(char*)"MYPATH=YOUCanSeeMe!!",
NULL
};

execle("./mycmd","mycmd",NULL,environ);
}
//一定是父进程
int status=0;
int ret=waitpid(id,&status,0);
if(ret==id)
{
sleep(2);
printf("父进程等待成功!\n");
}
return 0;
}

[ Linux ] 进程控制(下)----进程等待与进程程序替换_#include_42


这里我们看出还是程序崩溃了!

因为我们MYPATH环境变量还没有导入!

export MYPATH=“疯狂星期四!!”

[ Linux ] 进程控制(下)----进程等待与进程程序替换_运维_43

讲完这些接口我们发现还剩下的其他接口参数大致相同,我们掌握上面几个接口之后,我们就可以使用其他的接口!至此,进程控制结束,下篇博客我来带大家简易实现一个shell!!!


(本章完!)


网友评论