一、模拟实现僵尸进程, 孤儿进程
1.僵尸进程:僵尸进程是一个比较特殊的状态,当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵尸进程,而且僵尸进程会以终止状态保持在进程表中,并且会一直等待父进程读取退出户状态代码,那么当子进程退出,父进程在运行,但父进程没有读取到子进程状态,那么子进程就进入到僵尸状态。
1.1、实现一个僵尸进程
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main()
5 {
6 pid_t id = fork();
7 if(id < 0)
8 {
9 perror("fork");
10 return 1;
11 }
12 else if(id > 0){
13 printf("parent [%d] is sleeping...\n", getpid());
14 sleep(30);
15 }
16 else{
17 printf("child [%d] is begin...\n", getpid());
18 sleep(5);
19 exit(EXIT_SUCCESS);
20 }
21 return 0;
22 }
~
首先在另一个终端下执行
while :; do ps aux | grep static | grep -v grep; sleep 1; echo "#############"; done
启动监控
然后执行
./static
之后就可以看到子进程变成了僵尸进程
2.孤儿进程:相比于僵尸进程,如果父进程提前退出,那么子进程后退出, 这时子进程就称为“孤儿进程”,当然了OS不可能放任孤儿进程不管,孤儿进程被1号init进程领养,也由init进程回收。
2.1、实现孤儿进程
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4
5 int main()
6 {
7 pid_t id = fork();
8 if(id < 0)
9 {
10 perror("fork");
11 return 1;
12 }
13 else if(id == 0){//child
14 printf("I am child, pid is [%d]\n", getpid());
15 sleep(10);
16 }else{
17 printf("I am parent, pid is [%d]\n", getpid());
18 sleep(3);
19 exit(0);
20 }
21 return 0;
22 }
1 orphan_process:Orphan_process.c
2 gcc -o $@ $^
3
4 .PHONY:clean
5 clean:
6 rm -rf orphan_process
首先在另一个终端下执行
while :; do ps aux | grep orphan_process | grep -v grep; sleep 1; echo "#############"; done
启动监控
执行
./orphan_process
之后就可以看到子进程被回收
二、setenv, export等环境变量相关的函数和命令
环境变量里包含了程序运行时的完整路径,以便于我们在其他地方运行某个程序时,OS会在环境变量里搜索该程序的路径,然后运行。
- Linux中的环境变量
PATH //这个变量包含了一系列由冒号分隔开的目录,系统就从这些目录里寻找可执行文件。如果你输入的可执行文件(例如ls、rc-update或者emerge) 不在这些目录中,系统就无法执行它(除非你输入这个命令的完整路径,如/bin/ls)。
ROOTPATH //这个变量的功能和PATH相同,但它只罗列出超级用户(root)键入命令时所需检查的目录。
LDPATH //这个变量包含了一系列用冒号隔开的目录,动态链接器将在这些目录里查找库文件。
MANPATH //这个变量包含了一系列用冒号隔开的目录,命令man会在这些目录里搜索man页面。
INFODIR //这个变量包含了一系列用冒号隔开的目录,命令info将在这些目录里搜索info页面。
PAGER //这个变量包含了浏览文件内容的程序的路径(例如less或者more)。
EDITOR //这个变量包含了修改文件内容的程序(文件编辑器)的路径(比如nano或者vi)。
KDEDIRS //这个变量包含了一系列用冒号隔开的目录,里面放的是KDE相关的资料。
CONFIG_PROTECT //这个变量包含了一系列用空格隔开的目录,它们在更新的时候会被Portage保护起来。
CONFIG_PROTECT_MASK //这个变量包含了一系列用空格隔开的目录,它们在更新的时候不会被Portage保护起来。
- 环境变量命令
1.echo //显示某个环境变量值 echo $PATH
2.export //设置一个新的环境变量 export HELLO="hello" (可以无引号)
3.env //显示所有环境变量
4.set //显示本地定义的shell变量
5.unset //清除环境变量 unset HELLO
6.readonly //设置只读环境变量 readonly HELLO
- C语言中的
getenv(); setenv(); unsetenv();
函数可以设置或访问某一个环境变量。- getenv()函数
SYNOPSIS #include <stdlib.h> char *getenv(const char *name); char *secure_getenv(const char *name); Feature Test Macro Requirements for glibc (see feature_test_macros(7)): secure_getenv(): _GNU_SOURCE
根据getenv()函数的定义可以看出,一共有两个getenv()函数,其中
char *getenv(const char *name);
是如果所查找的环境变量不存在就返回一个NULL指针,存在就返回其地址,由于其返回值存放在一个数组里,所以不用担心再次查询会覆盖之前的值,而char *secure_getenv(const char *name);
也是同样的返回值,但其应用于线程安全。- setenv()函数
SYNOPSIS #include <stdlib.h> int setenv(const char *name, const char *value, int overwrite); Feature Test Macro Requirements for glibc (see feature_test_macros(7)): setenv(), unsetenv(): _BSD_SOURCE || _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 DESCRIPTION The setenv() function adds the variable name to the environment with the value value, if name does not already exist. If name does exist in the environment, then its value is changed to value if overwrite is nonzero; if overwrite is zero, then the value of name is not changed. This function makes copies of the strings pointed to by name and value (by contrast with putenv(3)).
setenv()函数,顾名思义可以设置环境变量,当环境变量中没有要添加的
name
时就添加该变量名,若存在就看overwrite
是否非零,若为零就不覆盖,若非零就覆盖。成功时返回0,错误时返回-1,并指出原因。- unsetenv()函数
SYNOPSIS #include <stdlib.h> int unsetenv(const char *name); Feature Test Macro Requirements for glibc (see feature_test_macros(7)): setenv(), unsetenv(): _BSD_SOURCE || _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 The unsetenv() function deletes the variable name from the environment. If name does not exist in the environment, then the function succeeds, and the environment is unchanged.
unsetenv()函数就是删除某个环境变量,若某个环境变量不存就返回成功,环境变量不作改变,返回值和setenv()函数一致。
- 指针变量
environ
指向的是一个包含所有环境变量的列表.使用以下代码可以打印出所有环境变量
可以看到以下结果1 #include <stdio.h> 2 extern char**environ; 3 int main () 4 { 5 char**path; 6 for (path =environ;*path !=NULL;++path) 7 printf ("%s \n ",*path); 8 return 0; 9 }
SSH_AUTH_SOCK=/run/user/1000/keyring/ssh SESSION_MANAGER=local/unix:@/tmp/.ICE-unix/1837,unix/unix:/tmp/.ICE-unix/1837 USERNAME=kui GNOME_SHELL_SESSION_MODE=classic PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/home/kui/.local/bin:/home/kui/bin MAIL=/var/spool/mail/kui DESKTOP_SESSION=gnome-classi QT_IM_MODULE=xim QT_QPA_PLATFORMTHEME=qgnomeplatform XDG_SESSION_TYPE=x11 PWD=/home/kui XMODIFIERS=@im=ibus LANG=zh_CN.UTF-8 GDM_LANG=zh_CN.UTF-8 GDMSESSION=gnome-classic HISTCONTROL=ignoredups XDG_SEAT=seat0 HOME=/home/kui SHLVL=2 GNOME_DESKTOP_SESSION_ID=this-is-deprecated XDG_SESSION_DESKTOP=gnome-classic LOGNAME=kui XDG_DATA_DIRS=/home/kui/.local/share/flatpak/exports/share/:/var/lib/flatpak/exports/share/:/usr/local/share/:/usr/share/ DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-8PBK3gNeEw,guid=e9d3af1ed81eabd51e3431735bef8722 LESSOPEN=||/usr/bin/lesspipe.sh %s WINDOWPATH=1 XDG_RUNTIME_DIR=/run/user/1000 DISPLAY=:0 XDG_CURRENT_DESKTOP=GNOME-Classic:GNOME COLORTERM=truecolor XAUTHORITY=/run/gdm/auth-for-kui-KUriSB/database_=./test