发信人: 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]
|
|