《UNIX环境高级编程》之进程环境
main函数
当内核执行C程序时,在调用main前先调用一个特殊的例程。可执行程序文件将此启动例程指定为程序的起始地址。启动例程从内核取得命令行参数和环境变量值。
进程终止
有8种方式使进程终止。
其中5种为正常终止:
-
从main返回
-
调用exit
-
调用_exit或_Exit
-
最后一个线程从其启动例程返回
-
从最后一个线程调用pthread_exit
异常终止有3种方式:
- 调用abort
- 接到一个信号
- 最后一个线程对取消请求作出响应。
退出函数
函数原型
#include <stdlib.h>
void exit(int status);
void _Exit(int status);
#include <unistd.h>
void _exit(int status);
说明
- exit函数总是对于所有打开流调用fclose函数。
- status是进程的终止状态
函数atexit
用途
登记进程终止时调用的函数。
函数原型
#include <stdlib.h>
int atexit(void (*func)(void));
返回值
若成功,返回0;若出错,返回非0.
说明
- exit调用这些函数的顺序与登记顺序相反。
- 一个进程最多可以登记32个函数。
- 一个终止处理程序被登记两次,则该函数也会被调用两次。
命令行参数
当执行一个新程序时,调用exec的进程可将命令行参数传递给该新程序。
环境表
每个进程都接收一张环境表,环境表是一个字符指针数组。全局变量environ则包含了该指针数组的地址。environ又称环境指针。指针数组为环境表,其中各指针指向的字符串为环境字符串。
extern char **environ;
C程序的存储空间布局
C程序由下列几部分组成:
- 正文段。
这是由CPU执行的机器指令部分。通常,正文段是可共享的,同时也是只读的。 - 初始化数据段
通常将此段称为数据段,它包含了程序中需明确地赋初值的变量。 - 未初始化数据段
通常将此段称为bss段,在程序开始执行之前,内核将此段中的数据初始化为0或空指针。未初始化数据段的内容并不存放在磁盘文件中。 - 栈
自动变量以及每次函数调用时时所需保存的信息都放在此段中。每次函数调用时,其返回地址以及调用者的环境信息都存放在栈中。 - 堆
通常在堆中进行动态存储分配。
在典型的存储空间安排中,从高地址到低地址依次为:命令行参数和环境变量、栈、堆、bss段、初始化数据段和正文段。
存储空间分配
函数malloc、calloc、realloc和free
函数原型
#include <stdlib.h>
void *malloc(size_t size);
void *calloc(size_t nobj, size_t size);
void *realloc(void *ptr, size_t newsize);
void free(void *ptr);
返回值
若成功,返回非空指针;若失败,返回NULL。
环境变量
函数getenv
用途
获取环境变量值。
函数原型
#include <unistd.h>
char *getenv(const char *name);
返回值
指向与name关联的value的指针;若未找到,返回NULL。
环境变量
变量 | 说明 |
---|---|
COLUMNS | 终端宽度 |
DATEMSK | getdate模板文件路径名 |
HOME | home起始目录 |
LANG | 本地名 |
LC_ALL | 本地名 |
LC_COLLATE | 本地排序名 |
LC_CTYPE | 本地字符分类名 |
LC_MESSAGES | 本地消息名 |
LC_MONETARY | 本地货币编辑名 |
LC_NUMERIC | 本地数字编辑名 |
LC_TIME | 本地日期/时间格式名 |
LINES | 终端高度 |
LOGNAME | 登录名 |
MSGVERB | fmtmsg处理的消息组成部分 |
NLSPATH | 消息类模板序列 |
PATH | 搜索可执行文件的路径前缀列表 |
PWD | 当前工作目录的绝对路径名 |
SHELL | 用户首选的shell名 |
TERM | 终端类型 |
TMPDIR | 在其中创建临时文件的目录路径名 |
TZ | 时区信息 |
函数putenv、setenv和unsetenv
用途
- 函数putenv取其形式为name=value的字符串,将其放入环境表中。如果name已经存在,则先删除其原来的定义。
- setenv将name设置为value。如果环境中name已经存在,如果rewrite非0,则首先删除其现有的定义;如果rewrite为0,则不删除其现有定义。
- unsetenv删除name的定义。即使不存在这种定义也不算出错。
函数原型
#include <stdlib.h>
int putenv(char *str);
// 若成功,返回0;若出错,返回非0。
int setenv(const char *name, const char *value, int rewrite);
int unsetenv(const char *name);
// 若成功,返回0;若出错,返回非-1。
函数setjmp和longjmp
用途
跨越函数执行跳转功能。
函数原型
#include <setjmp.h>
int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int val);
返回值
若直接调用,返回0;若从longjmp返回,则为非0。
函数fetrlimit和setrlimit
用途
查询和更改进程的资源限制。
函数原型
#include <sys/resource.h>
int getrlimit(int resource, struct rlimit *rlptr);
int setrlimit(int resource, const struct rlimit *rlptr);
返回值
若成功,返回0;若出错,返回非0。
rlimit的定义
struct rlimit
{
rlim_t rlim_cur; // 软限制:当前限制
rlim_t rlim_max; // 硬限制:rlim_cur的最大值
};
更改资源限制的规则
- 任何一个进程都可以将一个软限制值更改为小于或等于其硬限制值。
- 任何一个进程都可以降低其硬限制值,但它必须大于或等于其软限制值。这种降低对普通用户而言是不可逆的。
- 只有超级用户进程可以提高硬限制值。
常量RLIM_INFINITY执行了一个无限量的限制。
resource参数可以提高硬限制值。
限制 | 说明 |
---|---|
RLIMIT_AS | 进程总的可用存储空间的最大长度(字节)。这影响到sbrk函数和mmap函数。 |
RLIMIT_CORE | core文件的最大字节数,其值为0则阻止创建core文件。 |
RLIMIT_CPU | CPU时间的最大量值(秒),当超过此软限制时,向该进程发送SIGXCPU信号。 |
RLIMIT_DATA | 数据段的最大字节长度(初始化数据段、未初始以及堆的总和)。 |
RLIMIT_FSIZE | 可创建的文件的最大字节长度。当超过此软限制时,则向该进程发送SIGXFSZ信号。 |
RLIMIT_MEMLOCK | 一个进程使用mlock能够锁定在存储空间中的最大字节长度。 |
RLIMIT_MSGQUEUE | 进程为POSIX队列可分配的最大存储字节数。 |
RLIMIT_NICE | 为了影响进程的调度优先级,nice值可设置的最大限制。 |
RLIMIT_NOFIFE | 每个进程能打开的最多文件数。 |
RLIMIT_NPROC | 每个实际用户ID可拥有的最大子进程数。 |
RLIMIT_NPTS | 用户可同时打开的伪终端。 |
RLIMIT_RSS | 最大驻内存集字节长度。如果可用的物理存储器非常少,则内核从进程出取回超过RSS的部分。 |
RLIMIT_SBSIZE | 在任意时刻,一个用户可以占用的套接字缓冲区的最大长度。 |
RLIMIT_SIGPENDING | 一个进程可排队的信号最大数量。 |
RLIMIT_STACK | 栈的最大字节长度。 |
RLIMIT_SWAP | 用户可消耗的交换空间的最大字节数。 |
RLIMIT_VMEM | RLIMIT_AS的同义词。 |