您的位置:首页 > 运维架构 > Linux

Linux下fork()&vfork()的区别、getenv()&setenv()函数以及僵尸进程、孤儿进程讲解

2018-03-14 12:26 896 查看
在讲解僵尸进程前,我们先来说说其它知识,因为我们一会的代码需要用一个叫fork()的系统调用来创建子进程,所以我们先来聊聊fork()这个系统调用。

fork()、vfork()的区别:

#include<unistd.h>

pid_t fork(void);
//pid_t为int的类型别名
//fork()是一个比较特殊的函数,调用成功返回两个值,调用失败返回-1.
//那么到底fork()调用成功是如何返回两个值的呢?原来,fork()是用来
//创建子进程的,一但fork()调用成功,便会以父进程为模板创建子进程(
//代码段共享、数据段(写时拷贝)的拷贝),父、子进程都从fork()的下一句指令
//开始执行,但父、子进程的执行顺序无法确定,依赖于调度器的调度,父进程
//返回子进程的pid,子进程返回0,对于调用失败的情况可能有以下的两种情况,
//1)内存不足,内核没有足够的空间创建管理进程的数据结构(task_struct)
//2)进程数已经达到系统规定的上限
//与vfork()相关的还有一个叫做vfork()的函数,请看下面讲解:

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

pid_t vfork(void);
//vfork()的行为基本类似fork(),但两者有以下区别:
//1)fork()之后,子进程和父进程共享代码段、数据段写时拷贝,
//vfork()之后,代码段、数据段均共享。
//2)fork()、之后父、子进程的调度顺序依赖于调度器,vfork()之后,
//子进程先执行,在子进程调用exec()或_exit()之后父进程才可运行,
//不调用exec()或_exit(),则出现段错误,在调用exec()或_exit()之前,
//依赖父进程的动作,则会出现死锁。


僵尸进程:

所谓僵尸进程,是指那些父进程还在运行,子进程已经退出,但是父进程并没有查看子进程的退出状态,子进程一直以终止状态(Z状态)保存在进程表中等待父进程查看退出状态,此时,子进程便为僵尸进程。

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

int main(){
pid_t ret = fork();
if(ret < 0){
//fork失败,打印错误信息
perror("fork ");
return 1;

}else if(ret > 0){
//father进程
printf("father: pid_t = %d begin\n",getpid());//打印父进程pid
sleep(30);//延时30s
printf("father is end!\n");
}else{
//child进程
printf
c141
("child: pid_t = %d is begin...\n",getpid());//打印子进程pid
sleep(5);
printf("child: is end\n");
}
return 0;
}


运行程序,利用ps aux | grep zombieprocess指令查看进程状态,结果如下:

程序运行结果:



子进程结束前:



子进程结束后:



注意查看第八列的状态。

孤儿进程:

孤儿进程是指:父进程运行提前结束,子进程还在运行时,子进程便叫做孤儿进程。

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

int main(){
pid_t ret = fork();
if(ret < 0){
perror("fork:");
return 1;
}else if(ret == 0){
//child
printf("child pid:%d is begin!\n",getpid());
sleep(20);
printf("child father id:%d \n",getppid());
printf("child is end! \n");
}else{
//father
printf("father pid:%d is begin!\n",getpid());
sleep(5);
printf("father is end!\n");
}
return 0;
}


结果:



1号进程为init进程。

环境变量:

下面简单的介绍关于环境变量的指令与函数。

echo $env_name
:此命令查看相应环境变量的值。env_name为环境变量的名字。

export env_name="env_value"
:此命令创建一个新的环境变量。env_name为环境变量名,env_value为环境变量的值。

env
:查看所有环境变量。

后面再介绍关于环境变量的两个函数getenv()、setenv():

char *getenv(const char *name);


此函数获得相应环境变量的值,参数为环境变量的字符串,成功返回对应变量的值字符串,失败返回空指针。

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

int main(){
//char *getenv(const char *name);
char *env = getenv("PATH");
if(env){
printf("%s\n",env);
}
return 0;
}


输出结果:

[DELL@MiWiFi-R1CL-srv class_code]$ ./environ
/usr/java/jdk/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/home/DELL/.local/bin:/home/DELL/bin:./
[DELL@MiWiFi-R1CL-srv class_code]$


int setenv(const char *name, const char *value, int overwrite);


此函数用于创建环境变量或改变环境变量的值,name为所要改变或创建环境变量的值,value为环境变量的值,overwrite为标志位,当环境变量不存在时,无论overwrite为何值创建环境变量并以value赋值,当环境变量存在时,若overwrite非0时改变环境变量的值,当overwrite为0时忽略value的值,函数调用成功返回0,失败返回-1。

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

int main(){

//int setenv(const char *name, const char *value, int overwrite);
int ret = setenv("MYENV","hello world",1);
if(ret == 0){
printf("MYENV:");
char *env = getenv("MYENV");
if(env){
printf("%s\n",env);
}else{
perror("getenv:");
}
}else{
perror("setenv:");
}
return 0;
}


输出结果:

[DELL@MiWiFi-R1CL-srv class_code]$ ./environ
MYENV:hello world
[DELL@MiWiFi-R1CL-srv class_code]$
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐