一、环境变量
1、环境变量一般指在OS中用来指定OS运行环境的一些参数。
环境变量是变量,有变量名和变量内容。
环境变量通常具有某些特殊用途,在系统中通常具有全局特性
2、常见的环境变量
-
PATH*: 指定命令的搜索路径
-
HOME*: 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
-
HISTSIZE*: 指保存历史命令记录的条数
-
SHELL*: 当前Shell,它的值通常是/bin/bash。
3、查看环境变量
env 所有的环境变量
echo 【echo $HOME】
getenv() 【参数为环境变量名字符串】
4、PATH环境变量
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/hb/bin
搜索时,现在第一个:号前搜索,搜不到在去第一个:和第二个:之间去搜索……最后找不到会报错
5、添加环境变量的内容
PATH=$PATH:/home/hb/bit-code/31_class/linux/2_class
【上述命令可以添加,但不建议,建议采用下面的命令】
export PATH=$PATH:/home/hb/bit-code/31_class/linux/2_class
【不仅赋值,还要导出环境变量】
6、HOME环境变量
当前用户的主工作目录
/home/du
/root
【cd ~ 即转到当前用户的主工作目录 =cd $HOME
7、HISTSIZE
能够保留的历史命令行数
8、SHELL环境变量
shell是所有外壳程序的总和
用户通过shell与OS联系
bash是shell的一种
【echo $SHELL /bin/bash】
9、 创建一个新的环境变量
eg1:
MYENV_VAL=4321abcd 【直接新建变量】
env | grep MYENV_VAL 【输出错误,MYENV_VAL不存在。 env只输出环境变量】
echo $MYENV_VAL 【可以输出,得到4321abcd】
set 【set不仅输出环境变量也输出其他符号】
eg2:
export MYENV_VAL
env | grep MYENV_VAL 【可以输出,结果为MYENV_VAL=4321abcd】
echo $MYENV_VAL 【可以输出,得到4321abcd】
set | grep MYENV_VAL 【得到MYENV_VAL=4321abcd】
【注:export可以将本地变量转变为环境变量,eg1中MYENV_VAL未经export,所以只是本地变量,不能被env展示出】
【本地变量不能被子进程拿到,但从bash开始(包括bash)其下的所有进程都可以看到环境变量】
10、unset
unset MYENV_VAL 取消环境变量
二、程序地址空间
1、虚拟地址空间(进程地址空间)!=程序地址空间
2、c语言打出的地址是虚拟地址
虚拟地址最终要转化为物理地址
3、例子:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 0;
int main()
{
pid_t id = fork();
if(id < 0){
perror("fork");
return 0;
}
else if(id == 0){ //child,⼦子进程肯定先跑完,也就是⼦子进程先修改,完成之后,⽗父进程再读取
g_val=100;
printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
}else{ //parent
sleep(3);
printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
}
sleep(1);
return 0;
}
结果:
//与环境相关,观察现象即可
child[3046]: 100 : 0x80497e8
parent[3045]: 0 : 0x80497e8
我们发现,父子进程,输出地址是一致的,但是变量内容不一样!能得出如下结论:
-
变量内容不一样,所以父子进程输出的变量绝对不是同一个变量但地址值是一样的,说明,该地址绝对不是物理地址!
-
在Linux地址下,这种地址叫做 虚拟地址
-
我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址用户一概看不到,由OS统一管理。过程图见下:
4、虚拟地址空间在linux内核上其实也就是一个结构体,叫做m_struct。
虚拟地址空间对物理内存有保护作用。
5、创建一个进程需要做的事:
-
PCB
-
m_struct
-
页表(用户级页表,每个进程都有一个)
三、vfork函数
也是用来创建子进程,但是
vfork用于创建一个子进程,而子进程和父进程
共享地址空间。fork的子进程具有独立地址空间
vfork
保证子进程先运行,在它调用exec或(exit)之后父进程才可能被调度运行。
关于共享地址空间:
eg1:
int glob = 100;
int main( void )
{
pid_t pid;
if ( (pid=
fork()
) == -1 ) perror("fork"),exit(1);
if (pid == 0 ) { // child
printf("before:child glob %d\n", glob);
glob = 200;
printf("after:child glob %d\n", glob);
sleep(3);
exit(1);
} else { // parent
printf("parent glob %d\n", glob);
}
return 0;
}
//结果:
[root@localhost linux]# ./a.out
parent glob 100
[root@localhost linux]#child glob 100
child glob 100
eg2:
int glob = 100;
int main( void )
{
pid_t pid;
if ( (pid=
vfork()) == -1 ) perror("fork"),exit(1);
if (pid == 0 ) { // child
printf("before:child glob %d\n", glob);
glob = 200;
printf("after:child glob %d\n", glob);
sleep(3);
exit(1);
} else { // parent
printf("parent glob %d\n", glob);
}
return 0;
}
//结果:
[root@localhost linux]# ./a.out
before:child glob 100
after:child glob 200
parent glob 200 //3秒后输出
【补:】
(1)main函数正确退出返回0,错误退出返回不同的退出码
(2)echo $? 查询退出码(只保存离其最近的一条命令的退出码)
(3)在当前程序的任何一个地方使用exit都会使进程终结,main函数不再返回return的值,而返回exit的值。eg:
eixt(123);……return 0;,则退出码为123。
(4)调用exit()退出和_exit退出的区别是:exit()在结束前会做一些收尾工作,而_exit会强制退出。