首页 > 代码库 > 进程篇(1: 进程运行环境)--请参照本博客“操作系统”专栏
进程篇(1: 进程运行环境)--请参照本博客“操作系统”专栏
2014年5月30日 下午1:40:59
1. Unix 进程执行环境:
1.1 终止处理程序:
ISO C 规定,一个程序可以登记多达32个函数,这些函数将由exit自动调用。我们称这些函数为终止处理程序(exit handler),并调用atexit函数来登记这些函数。该函数的原型如下:
2
3 int atexit(void (*function)(void));
exit调用这些终止程序的顺序与他们登记时的顺序相反(先登记后调用)。同一个函数如果被登记多次也会被调用多次。
下面我们来实际编写和登记一个终止处理程序:
a). linux man_pages 上的程序:
2 #include <stdlib.h>
3 #include <unistd.h>
4
5 void bye(void)
6 {
7 printf("That was all, folks\n");
8 }
9
10 int main(void)
11 {
12 long a;
13 int i;
14
15 a = sysconf(_SC_ATEXIT_MAX);
16 printf("ATEXIT_MAX = %ld\n",a);
17
18 i = atexit(bye);
19 if(i != 0)
20 {
21 fprintf(stderr,"cannot set exit function\n");
22 exit(EXIT_FAILURE);
23 }
24
25 exit(EXIT_SUCCESS);
26 }
程序的输出结果是:
That was all, folks
b) APUE 上面的例题:
2 #include <stdlib.h>
3
4 void exit_func1(void);
5 void exit_func2(void);
6 void exit_func3(void);
7
8 int main(void)
9 {
10 if(atexit(exit_func1) != 0)
11 printf("failed to register exit_func1!\n");
12 if(atexit(exit_func2) != 0)
13 printf("failed to register exit_func2!\n");
14 if(atexit(exit_func3) != 0)
15 printf("failed to register exit_func3!\n");
16 exit(0);
17 }
18
19 void exit_func1(void)
20 {
21 printf("This is the exit_func1!\n");
22 }
23
24 void exit_func2(void)
25 {
26 printf("This is the exit_func2!\n");
27 }
28
29 void exit_func3(void)
30 {
31 printf("This is the exit_func3!\n");
32 }
结果是:
This is the exit_func2!
This is the exit_func1!
显然推出处理函数的登记顺序和执行顺序是相反的!
1.2 命令行参数:
当执行一个程序时,调用exec的进程可以将命令行参数传递给新的进程!
2
3 int main(int argc,char *argv[])
4 {
5 int i;
6 for(i = 0; i < argc; i++) /* echo all command-line args */
7 printf("argv[%d]: %s\n",i,argv[i]);
8 return 0;
9 }
上面这个函数原样输出命令行参数:
./a.out This is me:
argv[1]: This
argv[2]: is
argv[3]: me
注意: C/C++的命令行参数是包含程序名称的! Java的命令行参数是不包含程序名称的!
下面是一段显示Java命令行参数的源代码:
2 {
3 public static void main(String argv[])
4 {
5 for(int i = 0; i < argv.length; i++)
6 System.out.printf("args[%d]: %s\n",i,argv[i]);
7 }
8 }
在shell中输入命令 java javaargs This is me 之后:
args[1]: is
args[2]: me
可以看到命令行参数是不包含程序名的!
1.3 环境表和指向指针的指针:
每个程序都会接收到一张环境表,和命令行参数列表一样,环境表也是一张字符指针数组。
但如何得到和修改环境表的某个表项?怎样得到整个环境表?
char *getenv(const char *name);
/*
* The getevn() function searches the environment list to find the environment variable name, and
*returns a pointer to the corresponding value string
*/
下面我们通过实际程序来验证如何得到特定环境变量:
2 #include <stdlib.h>
3
4 int main(void)
5 {
6 printf("The Env Var PATH is:\n");
7 printf("%s\n",getenv("PATH"));
8
9 printf("The Env Var HOME is:\n");
10 printf("%s\n",getenv("HOME"));
11
12 printf("The Env Var HOME is:\n");
13 printf("%s\n",getenv("JAVA_HOME"));
14
15 exit(0);
16 }
上面的程序在我的电脑上的运行结果是:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/jvm/jdk/bin:/usr/lib/jvm/jdk/jre/bin:/usr/lib/jvm/jdk/bin:/usr/lib/jvm/jdk/jre/bin
The Env Var HOME is:
/home/jiangheng
The Env Var HOME is:
/usr/lib/jvm/jdk
当然你的电脑上的结果根据你的系统配置而异。
那么如何设置新的环境变量呢? setenv 的原型如下:
int setenv(const char *name,const char *value,int overwrite);
int unsetenv(const char *name);
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)).
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.
*/
下面我们通过程序来验证对环境变量的修改:
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *path = getenv("PATH"); /* get the old path */
puts("Old PATH: ");
puts(path);
path = strcat(path,":/home/jiangheng"); /* new PATH */
if(setenv("PATH",path,1) != 0)
printf("Failed to set PATH!\n");
char *new_path = getenv("PATH"); /* get the new path */
puts("");
puts("New PATH: ");
puts(new_path);
exit(0);
}
首先打印原来的PATH,然后再打印修改后的PATH,结果如下:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/jvm/jdk/bin:/usr/lib/jvm/jdk/jre/bin:/usr/lib/jvm/jdk/bin:/usr/lib/jvm/jdk/jre/bin
New PATH:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/jvm/jdk/bin:/usr/lib/jvm/jdk/jre/bin:/usr/lib/jvm/jdk/bin:/usr/lib/jvm/jdk/jre/bin:/home/jiangheng
显然我们修改了环境变量PATH!
那么如何得到所有环境变量的值呢? 下面是得到所有环境变量的源代码:
2 #include <stdlib.h>
3
4 extern char **environ;
5
6 int main(void)
7 {
8 int i = 0;
9 while(environ[i] != NULL)
10 {
11 puts(environ[i]);
12 i++;
13 }
14 exit(0);
15 }
程序的结果如下:
SSH_AGENT_PID=1819
XDG_SESSION_ID=c1
CLUTTER_IM_MODULE=xim
GPG_AGENT_INFO=/run/user/1000/keyring-NpJvov/gpg:0:1
TERM=xterm
SHELL=/bin/bash
VTE_VERSION=3406
XDG_SESSION_COOKIE=7cec1ada7aecdca275c3573653082170-1401399175.732373-1244795985
CLUTTER_DISABLE_XINPUT=1
WINDOWID=39845896
GNOME_KEYRING_CONTROL=/run/user/1000/keyring-NpJvov
USER=jiangheng
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:
SSH_AUTH_SOCK=/run/user/1000/keyring-NpJvov/ssh
SESSION_MANAGER=local/jiangheng-Lenovo-U410:@/tmp/.ICE-unix/1720,unix/jiangheng-Lenovo-U410:/tmp/.ICE-unix/1720
USERNAME=jiangheng
DEFAULTS_PATH=/usr/share/gconf/default.default.path
XDG_CONFIG_DIRS=/etc/xdg/xdg-default:/etc/xdg
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/jvm/jdk/bin:/usr/lib/jvm/jdk/jre/bin:/usr/lib/jvm/jdk/bin:/usr/lib/jvm/jdk/jre/bin
DESKTOP_SESSION=default
GDM_XSERVER_LOCATION=local
PWD=/home/jiangheng/AUEP/process/pro_evn
XMODIFIERS=@im=fcitx
JAVA_HOME=/usr/lib/jvm/jdk
GNOME_KEYRING_PID=1644
LANG=zh_CN.UTF-8
MANDATORY_PATH=/usr/share/gconf/default.mandatory.path
MDM_XSERVER_LOCATION=local
GDMSESSION=default
SHLVL=1
XDG_SEAT=seat0
HOME=/home/jiangheng
GNOME_DESKTOP_SESSION_ID=this-is-deprecated
LOGNAME=jiangheng
QT4_IM_MODULE=xim
XDG_DATA_DIRS=/usr/share/default:/usr/share/gnome:/usr/local/share/:/usr/share/:/usr/share/mdm/
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-HZ9f5B9T2y,guid=0eb168d6e01b1cf3e3ccd3465387a78b
CLASSPATH=:/usr/lib/jvm/jdk/lib:/usr/lib/jvm/jdk/jre/lib:/usr/lib/jvm/jdk/lib:/usr/lib/jvm/jdk/jre/lib
MDMSESSION=default
TEXTDOMAIN=im-config
WINDOWPATH=7
XDG_RUNTIME_DIR=/run/user/1000
DISPLAY=:0
MDM_LANG=zh_CN.UTF-8
XDG_CURRENT_DESKTOP=GNOME
GTK_IM_MODULE=xim
TEXTDOMAINDIR=/usr/share/locale/
COLORTERM=gnome-terminal
XAUTHORITY=/home/jiangheng/.Xauthority
OLDPWD=/home/jiangheng
_=./a.out
显然我们通过extern char **environ;得到了所有的环境变量.