精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>编程开发>>C/C++>>资料汇编----------藏经阁>>Unix编程FAQ>>Unix编程FAQ第一章第1-2节

主题:Unix编程FAQ第一章第1-2节
发信人: tengel()
整理人: kevintz(2000-08-24 01:57:55), 站内信件
1进程控制
1.1创建信进程:fork()
1.1.1 fork()函数的功用?

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

pid_t fork(void);

fork()函数是从当前的进程创建一个新的进程.新的进程被称为子进程,而当前进
程是其父进程.你可通过fork()的返回值来判断出谁是父进程谁是子进程.父进程
从返回值获取子进程的pid,而子进程返回0值.以下这些简单的代码解释了fork()
的基本用法.

pid_t pid;
switch (pid = fork())
{
case -1:
    /* Here pid is -1, the fork failed */
    /* Some possible reasons are that you're */
    /* out of process slots or virtual memory */  
    perror("The fork failed!");
    break;
case 0:    /* pid of zero is the child */
    /* Here we're the child...what should we do? */    /* ... */
    /* but after doing it, we should do something like: */    _exit(0)
;
default:
    /* pid greater than zero is parent getting the child's pid */
    printf("Child's pid is %d\n",pid);
}

当然,你可以用if()...else...替换switch()语句,但以上语句是常用的写法.

知道父进程的那些项可被子进程继承那些不被继承是有帮助的.列表因unix实现的
不同而不同,所以对它可不要太在意.注意子进程只是获得父进程可继承项的一份
拷贝,而不是父进程实际的东西.

子进程可从父进程继承的项:

.进程信任权限 (real/effective/saved UIDs and GIDs) 
.环境
.栈 
.内存 
.打开文件标识符(note that the underlying file positions are shared bet
ween the parent and child, which can be confusing)
.close-on-exec 标志
.信号处理设置
.nice value 
.调度类 
.进程组ID 
.会话ID
.当前工作目录 
.根目录 
.创建文件的掩码 (umask) 
.资源许可 
.终端控制

父子进程间的不同:

.进程ID
.不同的父进程ID 
.文件标识符和目录流的各自的拷贝
.进程,文本(代码),数据和其他内存锁不被继承
.以tms结构的进程时间
.资源利用被设置为0
.未决的信号初始化为空
.通过timer_create创建的计时器不被继承
.异步输入和输出操作不被继承


1.1.2 fork() 与 vfork()的不同?

一些系统有一个系统调用vfork(),原意是设计一个系统开销较低的fork()版本.因
为fork()函数涉及到全部进程地址空间的拷贝,因此开销较大,所以引入了vfork(
)函数(in 3.0BSD). 

然而,自从vfork()被引入后,fork()的实现得到了很大的改进,最主要的是引入了
"写时拷贝技术",通过两个进程在修改一块内存之前引用相同的物理内存,来实现
进程地址空间的透明伪装.去除vfork的最主要的理由是,绝大多数系统都缺乏vfo
rk函数的最初完全功能.为了兼容,系统都仍然提供了vfork调用,他们都简单的调
用fork,二并不尝试仿效vfork的所有的语义。
因此,使用vfork和fork之间的不同是不明智的。事实上,除非你知道你为什么这
样做,否则使用vfork可能也是不明智的。
这意味着vfork的子进程必须仔细的避免修改父进程的变量。典型的,子进程一定
不从包含vfork调用的函数返回,而且他也必须不能调用exit()(如果需要退出,
应该调用_exit();事实上,对于正常的fork子进程也是一样)。
1。1。3为什么在fork的子进程分支中使用_exit更正确?
exit与_exit有一些微妙的不同,这些不同在fork,特别是vfork中,非常有意义

exit()和_exit()的基本不同是,exit执行清理关联用户模式的创建,调用用户补
充的清理函数,然而_exit仅仅有内核来清除进程。
在fork的子进程分支,使用exit通常是不正确的,因为他可能导致stdio缓冲被清
洗两次,而且临时文件被意想不到的删除。在C++代码中,情况更坏,因为静态对
象的析构函数可能被调用不正确的运行。(在一些特殊情况下,像守护进程,父
进程将调用_exit,而不是子进程;基本的规则,在绝大多数情况下,exit对于进
入main的每个条目将被仅仅调用一次)
在vfork的子进程分支,使用exit更加危险,因为他将影响到父进程的状态。
1。2环境变量
1。2。1如何在程序中get/set环境变量?
取得环境变量的值,可以使用getenv().
#include <stdlib.h>

char *getenv(const char *name);

设置环境变量的值,使用putenv()
#include <stdlib.h>

int putenv(char *string);

把指针传递给putenv之后,传递给putenv的字符串不能被释放,或者无效。这意
味着必须它必须是静态缓冲,或者是从堆上分配。字符串可以被释放,如果环境
变量被重定义,或者被其他调用putenv所删除。
记住环境变量是被继承的;每个进程拥有一个分别的环境的拷贝。因此,改变像
shell的其他进程的环境变量的值。
假设你想取得TERM环境变量的值,你可以使用如下代码:
char *envvar;

envvar=getenv("TERM");

printf("The value for the environment variable TERM is ");
if(envvar)
{
    printf("%s\n",envvar);
}
else
{
    printf("not set.\n");
}

如果你想创建一个叫MYVAR的新的环境变量,值为MYVAL,你可以这样做:
static char envbuf[256];

sprintf(envbuf,"MYVAR=%s","MYVAL");

if(putenv(envbuf))
{
    printf("Sorry, putenv() couldn't find the memory for %s\n",envbuf)
;
    /* Might exit() or something here if you can't live without it */

}

1。2。2如何读去所有环境?
如果你并不知道环境变量的名字,那么getenv()并不是很有用。在这种情况下,
你不得不深入到环境信息的存储。
一个全局变量,environ,保存一个指向环境字符串数组的指针,每个字符串为“
NAME=value”格式。一个空指针用来标识数组的结束。下面是一个没有多大价值
的打印当前环境的程序(像printenv):
#include <stdio.h>

extern char **environ;

int main()
{
    char **ep = environ;
    char *p;
    while ((p = *ep++))
        printf("%s\n", p);
    return 0;
}

通常情况下,环境变量也同过main的第三个(可选的)参数传递给main,也就是
说,上面的程序也可以这样写:
#include <stdio.h>

int main(int argc, char **argv, char **envp)
{
    char *p;
    while ((p = *envp++))
        printf("%s\n", p);
    return 0;
}

然而,考虑良好的可移植,这种方法并没有定义在posix标准(通常,也很少用)


--
                                           _
   O           @___       G               : \  
  /|__       /|/         /\|\             :  \
 /|/_       / /\         \ X_             :   \
  /  |     __/  \          | \      0     :    \
 /    0        0|          /              :     \

※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 210.14.224.186]

[关闭][返回]