📄 unix
字号:
Unit)的时间,包括:用户时<BR>
间,系统时间,用户各子进程合计时间,系统各子进程合计时间)<BR><BR>
* 资源使用(resource
utilizations)设定为0<BR><BR> *
阻塞信号集初始化为空集(译者注:原文此处不明确,译文根据fork函数手册页<BR>
稍做修改)<BR><BR> *
不继承由timer_create函数创建的计时器<BR><BR> *
不继承异步输入和输出<BR><BR>1.1.2 fork函数 与
vfork函数的区别在哪里里?<BR>-------------------------------------------<BR><BR>有些系统有一个系统调用‘vfork()’,它最初被设计成‘fork()’的较少额外支出<BR>(lower-overhead)版本。因为‘fork()’包括拷贝整个进程的地址空间,所以非常<BR>“昂贵”,这个‘vfork()’函数因此被引入。(在3.0BSD中)(译者注:BSD:<BR>Berkeley
Software
Distribution)<BR><BR>*但是*,自从‘vfork()’被引入,‘fork()’的实现方法得到了很大改善,最值得<BR>注意的是“写操作时拷贝”(copy-on-write)的引入,它是通过允许父子进程可访问<BR>相同物理内存从而伪装(fake)了对进程地址空间的真实拷贝,直到有进程改变内<BR>存中数据时才拷贝。这个提高很大程度上抹杀了需要‘vfork()’的理由;事实上,<BR>一大部份系统完全丧失了‘vfork()’的原始功能。但为了兼容,它们仍然提供<BR>‘vfork()’函数调用,但它只是简单地调用‘fork()’,而不试图模拟所有‘vfork()’<BR>的语义(semantics,
译文取自<<高级编程>>,指定义的内容和做法)。<BR><BR>结论是,试图使用任何‘fork()’和‘vfork()’的不同点是*很*不明智的。事实上,<BR>可能使用‘vfork()’根本就是不明智的,除非你确切知道你想*干什么*。<BR><BR>两者的基本区别在于当使用‘vfork()’创建新进程时,父进程将被暂时阻塞,而<BR>子进程则可以借用父进程的地址空间。这个奇特状态将持续直到子进程要么退<BR>出,要么调用‘execve()’,至此父进程才继续执行。<BR><BR>这意味着一个由‘vfork()’创建的子进程必须小心以免出乎意料地改变父进程的<BR>变量。特别的,子进程必须不从包含‘vfork()’调用的函数返回,而且必须不调<BR>用‘exit()’(如果它需要退出,它需要使用‘_exit()’;事实上,对于使用正常<BR>‘fork()’创建的子进程这也是正确的)(译者注:参见1.1.3)<BR><BR>1.1.3
为何在一个fork的子进程分支中使用_exit函数而不使用exit函数?<BR>-----------------------------------------------------------------<BR><BR>‘exit()’与‘_exit()’有不少区别在使用‘fork()’,特别是‘vfork()’时变得很<BR>突出。<BR><BR>‘exit()’与‘_exit()’的基本区别在于前一个调用实施与调用库里用户状态结构<BR>(user-mode
constructs)有关的清除工作(clean-up),而且调用用户自定义的清除程序<BR>(译者注:自定义清除程序由atexit函数定义,可定义多次,并以倒序执行),相对<BR>应,后一个函数只为进程实施内核清除工作。<BR><BR>在由‘fork()’创建的子进程分支里,正常情况下使用‘exit()’是不正确的,这是<BR>因为使用它会导致标准输入输出(译者注:stdio:
Standard Input
Output)的缓冲区被<BR>清空两次,而且临时文件被出乎意料的删除(译者注:临时文件由tmpfile函数创建<BR>在系统临时目录下,文件名由系统随机生成)。在C++程序中情况会更糟,因为静<BR>态目标(static
objects)的析构函数(destructors)可以被错误地执行。(还有一些特殊情<BR>况,比如守护程序,它们的*父进程*需要调用‘_exit()’而不是子进程;适用于绝<BR>大多数情况的基本规则是,‘exit()’在每一次进入‘main’函数后只调用一次。)<BR><BR>在由‘vfork()’创建的子进程分支里,‘exit()’的使用将更加危险,因为它将影响<BR>*父*进程的状态。<BR><BR>1.2
环境变量<BR>============<BR><BR>1.2.1 如何从程序中获得/设置环境变量?<BR>--------------------------------------<BR>获得一个环境变量可以通过调用‘getenv()’函数完成。<BR><BR>
#include
<stdlib.h><BR><BR>
char *getenv(const char
*name);<BR><BR>设置一个环境变量可以通过调用‘putenv()’函数完成。<BR><BR>
#include
<stdlib.h><BR><BR>
int putenv(char
*string);<BR><BR>变量string应该遵守"name=value"的格式。已经传递给putenv函数的字符串*不*能够被<BR>释放或变成无效,因为一个指向它的指针将由‘putenv()’保存。这意味着它必须是<BR>在静态数据区中或是从堆(heap)分配的。如果这个环境变量被另一个‘putenv()’的<BR>调用重新定义或删除,上述字符串可以被释放。<BR><BR>/*
译者增加:<BR><BR>因为putenv()有这样的局限,在使用中经常会导致一些错<BR>误,GNU
libc 中还包括了两个BSD风格的函数:<BR>#include
<stdlib.h><BR>int setenv(const char *name,
const char *value, int replace);<BR>void
unsetenv(const char
*name);<BR><BR>setenv()/unsetenv()函数可以完成所有putenv()能做的事。setenv()
可以不受指针<BR>限制地向环境变量中添加新值,但传入参数不能为空(NULL)。当replace为0时,如<BR>果环境变量中已经有了name项,函数什么也不做(保留原项),否则原项被覆盖。<BR>unsetenv()是用来把name项从环境变量中删除。注意:这两个函数只存在在BSD和GNU<BR>库中,其他如SunOS系统中不包括它们,因此将会带来一些兼容问题。我们可以用<BR>getenv()/putenv()来实现:<BR><BR>int
setenv(const char *name, const char
*value, int replace)<BR>{<BR> char
*envstr;<BR><BR> if (name == NULL ||
value ==
NULL)<BR> return
1;<BR> if (getenv(name)
!=NULL)<BR>
{<BR> envstr
= (char *) malloc(strlen(name) + strlen(value) +
2);<BR> sprintf
(envstr, "%s=%s", name,
value);<BR> if
(putenv(envstr));<BR>
return 1;<BR>
}<BR> return
0;<BR>}<BR>*/<BR><BR>记住环境变量是被继承的;每一个进程有一个不同的环境变量表拷贝(译者注:<BR>从core文件中我们可以看出这一点)。结果是,你不能从一个其他进程改变当前<BR>进程的环境变量,比如shell进程。<BR><BR>假设你想得到环境变量‘TERM’的值,你需要使用下面的程序:<BR><BR>
char *envvar;<BR><BR>
envvar=getenv("TERM");<BR><BR>
printf("The value for the environment variable
TERM is ");<BR>
if(envvar)<BR>
{<BR>
printf("%s\n",envvar);<BR>
}<BR>
else<BR>
{<BR>
printf("not set.\n");<BR>
}<BR><BR>现在假设你想创建一个新的环境变量,变量名为‘MYVAR’,值为‘MYVAL’。<BR>以下是你将怎样做:<BR><BR>
static char
envbuf[256];<BR><BR>
sprintf(envbuf,"MYVAR=%s","MYVAL");<BR><BR>
if(putenv(envbuf))<BR>
{<BR>
printf("Sorry, putenv() couldn't find the memory
for
%s\n",envbuf);<BR>
/* Might exit() or something here if you can't
live without it */<BR>
}<BR><BR>1.2.2
我怎样读取整个环境变量表?<BR>--------------------------------<BR><BR>如果你不知道确切你想要的环境变量的名字,那么‘getenv()’函数不是很有用。<BR>在这种情况下,你必须更深入了解环境变量表的存储方式。<BR><BR>全局变量,‘char
**envrion’,包含指向环境字符串指针数组的指针,每一个字<BR>符串的形式为‘“NAME=value”’(译者注:和putenv()中的“string”的格式相同)。<BR>这个数组以一个‘空’(NULL)指针标记结束。这里是一个打印当前环境变量列表<BR>的小程序(类似‘printenv’)。<BR><BR>
#include
<stdio.h><BR><BR>
extern char
**environ;<BR><BR> int
main()<BR>
{<BR>
char **ep =
environ;<BR>
char
*p;<BR>
while ((p =
*ep++))<BR>
printf("%s\n",
p);<BR>
return 0;<BR>
}<BR><BR>一般情况下,‘envrion’变量作为可选的第三个参数传递给‘main()’;就是说,<BR>上面的程序可以写成:<BR><BR>
#include
<stdio.h><BR><BR>
int main(int argc, char **argv, char
**envp)<BR>
{<BR>
char
*p;<BR>
while ((p =
*envp++))<BR>
printf("%s\n",
p);<BR>
return 0;<BR>
}<BR><BR>虽然这种方法被广泛的操纵系统所支持(译者注:包括DOS),这种方法事实上并<BR>没有被POSIX(译者注:POSIX:
Portable Operating System
Interace)标准所定义。(一<BR>般的,它也比较没用)<BR><BR>1.3
我怎样睡眠小于一秒?<BR>========================<BR><BR>在所有Unix中都有的‘sleep()’函数只允许以秒计算的时间间隔。如果你想要更<BR>细化,那么你需要寻找替换方法:<BR><BR>
* 许多系统有一个‘usleep()’函数<BR><BR> *
你可以使用‘select()’或‘poll()’,并设置成无文件描述符并试验;一个普<BR>
遍技巧是基于其中一个函数写一个‘usleep()’函数。(参见comp.unix.questions<BR>
FAQ 的一些例子)<BR><BR> *
如果你的系统有itimers(很多是有的)(译者注:setitimer和getitimer是两个操作<BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -