本章主要介绍了Unix进程环境,包含main函数是如何被调用的,命令行参数如何传递,存储方式布局,分配存储空间,环境变量,进程终止方法,全局跳转longjmp和setjmp函数及进程的资源限制。
main函数的原型为int main(int argc,char *argv[]);其中argc是命令行参数的数目,argv是指向参数的各个指针构成的数组。当内核执行C程序时,使用一个exec函数,在调用main函数前线调用一个特殊的启动例程,从内核获取命令行参数和环境变量。
进程终止分为正常终止和异常终止。正常终止包括:(1)从main返回,(2)调用exit();(3)调用_exit或者_Exit();(4)最后启动一个线程从其启动例程返回;(5)最后一个线程调用pthread_exit。异常终止包括:(1)调用abort();(2)接收到一个信号并终止;(3)最后一个线程对取消请求做出响应。
1、exit函数系列:_exit和_Exit函数立即进入内核,而exit函数则执行清理处理(如关闭标准I/O流,执行各终止处理程序)。在main函数执行return (0)与exit(0)是等价的。
#include
void _exit(int status);
#include
void exit(int status);
void _Exit(int status);
2、atexit函数,用来登记终止处理程序,一个进程可以登记多达32个函数,这些函数将有exit自动调用,调用顺序与登记顺序相反,同一个函数可以登记多次,则也会被调用多次。函数原型如下:
#include <stdlib.h>
int atexit(void (*function)(void)); //成功返回0,否则返回非0值
内核使程序执行的唯一方法是调用一个exec函数,终止的唯一方法是显式或者隐式地通过exit函数调用_exit()或_Exit(),也可以非自愿的由一个信号使其终止。
写个程序进程练习,程序如下:
#include
#include
void exit_func1();
void exit_func2();
int main()
{
//登记终止处理函数
atexit(exit_func2);
atexit(exit_func1);
atexit(exit_func2);
printf("Test exit and atexit.\n");
exit(0);
}
void exit_func1()
{
printf("exit_func1() is called.\n");
}
void exit_func2()
{
printf("exit_func2() is called.\n");
}
程序执行结果如下:
命令行参数,当执行一个程序时,调用exec的进程可将命令行参数传递给该新程序,进程间通信数据传输进程用到。写个程序输出其命令行参数,程序如下:
#include
#include
int main(int argc,char *argv[])
{
int i;
for(i=0;i
测试结果如下:
存储器分配函数:
#include
void *malloc(size_t size);
void *calloc(size_t nmemb,size_t size);
void *realloc(void *ptr, size_t size); //更改以前分配区的长度
void free(void *ptr);
写个程序练习函数的使用:
#include
#include
#include
int main()
{
int n;
int *pData;
printf("Enter the number: ");
scanf("%d",&n);
pData = (int*)malloc(sizeof(int)*n);
memset(pData,0,sizeof(int)*n);
printf("pData address is :%p\n",pData);
free(pData);
pData = (int*)calloc(n,sizeof(int));
printf("pData address is :%p\n",pData);
pData=realloc(pData,sizeof(int)*(n+10));
printf("pData address is :%p\n",pData);
free(pData);
exit(0);
}
环境变量:形式为name=value,环境变量可以在用进程进程间通信,exec函数可以通过环境变量进程传参数,例如在CGI程序中用到HTTP协议get和post方法对应的环境变量。环境变量可用于所有的子进程,这包括编辑器、脚本和应用。环境变量操作函数如下:
#include
char *getenv(const char *name); //指向与name关联的value的指针
int putenv(char *string); //取形式为name=value的字符串,将其放到环境表中
int setenv(const char *name, const char *value, int overwrite); //将name设置为value
int unsetenv(const char *name); //删除name的定义
int clearenv(void); //删除环境表中所有项
写个程序进行环境变量的读取设置及删除。程序如下:
#include
#include
#include
int main()
{
char *name;
char *value;
char *str = "LENGTH=10";
char *pvalue;
name = "QUERY";
value = "Hello,world";
//设置环境变量,1表示若那么存在,则先先删除
setenv(name,value,1);
//用字符串设置环境变量
putenv(str);
//取环境变量的值
pvalue = getenv(name);
printf("%s=%s\n",name,pvalue);
pvalue = getenv("LENGTH");
printf("LENGTH=%s\n",pvalue);
unsetenv("LENGTH");
//取系统HOME环境变量的值
pvalue = getenv("HOME");
printf("HOME=%s\n",pvalue);
exit(0);
}
程序执行结果如下:
全局跳转函数setjmp和longjmp:解决跨越函数跳跃,处理发生在深层次嵌套函数调用中出错情况非常有用。全局或者静态变量的值在执行longjmp是保持不变。函数原型如下:
int clearenv(void);
#include
int setjmp(jmp_buf env); //返回值为0为直接调用,从longjmp调用返回非0值
int sigsetjmp(sigjmp_buf env, int savesigs);
一般用法是:设置一个全局的jmp_buf变量,在主进程中调用setjmp()设置跳转变量,如果后面的函数出现错误,调用longjmp设置一个值,说明函数调用出错。写个程序来表达用法,程序如下:
#include
#include
#include
#include
void func1();
void func2();
void func3();
//定义一个全局的跳转变量
jmp_buf jmpbuffer;
int main()
{
int ret;
//获取返回值,0为直接调用
ret=setjmp(jmpbuffer);
switch(ret)
{
case 1:
printf("func1 is error.\n");
exit(-1);
case 2:
printf("func2 is error.\n");
exit(-1);
case 3:
printf("func3 is error.\n");
exit(-1);
}
func1();
exit(0);
}
void func1()
{
//longjmp(jmpbuffer,1);
func2();
}
void func2()
{
//longjmp(jmpbuffer,2);
func3();
}
void func3()
{
//设置跳转
longjmp(jmpbuffer,3);
}
程序执行结果如下:
进程资源限制函数:getrlimit和setrlimit,资源结果和函数原型如下:
struct rlimit {
rlim_t rlim_cur; /* Soft limit */
rlim_t rlim_max; /* Hard limit (ceiling for rlim_cur) */
};
#include
int getrlimit(int resource, struct rlimit *rlim);
int setrlimit(int resource, const struct rlimit *rlim);