进程是非常重要的概念,学习进程自我感觉最好的学习方式是从进程的结构上去理解进程,先从浅再入深,循环渐进,下面就总结一下最近对进程的环境的学习总结吧。
(一)程序的存储空间布局
每一个程序都包括以下部分:
1. 正文段 :CPU执行的机器指令部分,通常是可以共享的,并且是只读的以防止程序意外修改。
2. 已初始化数据段: 包含明确赋初值的变量。
3. 未初始化数据段: 又称为BBS段,函数外为初始化的变量。
4. 栈: 保存自动变量以及每次函数调用时所需保存的信息。
5. 堆:常用与动态份分配存储空间。
6. 命令行参数与环境变量:一些程序需要的环境变量。
其存储空间安排如图所示:
(二)进程的关闭
正常终止:
(1)从main函数返回。
(2)调用exit()函数,退出时执行清理工作。
(3)调用_exit()函数或者_Exit()函数,直接进入内(即直接退出)。
(4)最后一个线程从其启动例程返回。
(5)从最后一个线程调用pthread_exit()函数。
异常终止:
(1)调用abort()函数。
(2)接受到一个信号。
(3)最后一个线程最取消请求做出响应。
注意: return退出与exit退出是不一样的,return是退出该函数,而exit是退出该进程,但是当在mian函数时我自己感觉他们是相同的
例如:
#include <stdio.h>
#include <stdlib.h>
void fun1()
{
printf("jingtiki\n");
return ;
}
void fun2()
{
printf("jjjjjjjj\n");
exit(0);
}
int main()
{
fun2();//直接退出main
fun1();//只是退出fun1函数,main继续运行
printf("hhhhhh\n");
return 0;
}
另外: atexit()函数 即退出时先执行处理函数
#include <stdlib.h>
int atexit(void (*function)(void));
例如:
#include <stdio.h>
#include <stdlib.h>
void fun1()
{
printf("fun1\n");
}
void fun2()
{
printf("fun2\n");
}
int main()
{
if( atexit(fun1) != 0 )
{
perror("atexit err\n");
exit(EXIT_FAILURE);
}
if( atexit(fun2) != 0 )
{
perror("atexit err\n");
exit(EXIT_FAILURE);
}
if( atexit(fun2) != 0 )
{
perror("atexit err\n");
exit(EXIT_FAILURE);
}
return 0;
}
(三)环境变量
(1)环境表
每此运行程序都会有一张环境表,与参数表一样,环境表也是一个字符串指针数组,其中每个指针包含以NULL结束的c字符串的地址,全局变量environ则包含了指针数组的地址。图示如下:
(2)获得环境变量
#include <stdlib.h>
char *getenv(const char *name);
例如:
#include <stdio.h>
#include <stdlib.h>
int main()
{
const char *path = "PATH";
char * p = getenv("PATH");
if( p == NULL )
{
perror("get environment err\n");
exit(EXIT_FAILURE);
}
printf("PATH: %s",p);
return 0;
}
(3)设置环境变量
#include <stdlib.h>
int putenv(char *string);
#include <stdlib.h>
int setenv(const char *name, const char *value, int overwrite);
int unsetenv(const char *name);
- 如果putenv要设置的环境变量已经存在,则使用现定义。
- 如果setenv要设置的环境变量name已经存在,那么若rewrite非0,则删除现有的定义,那么若rewrite为0,则不删除现有的定义。
- unsetenv删除name的定义。
注意设置的环境变量只对该程序有效。
(四)setjmp函数与longjmp函数
#include <setjmp.h>
int setjmp(jmp_buf env);
int sigsetjmp(sigjmp_buf env, int savesigs);
(1)作用: 检测深层函数的错误信息
(2)实现步骤:
- 首先调用setjmp函数获得此时进程的栈状态,有两个返回值,第一次是直接调用所以返回0。
- 在深层函数中调用longjmp函数,如果该函数中出现错误,将会返回主函数,此时造成setjmp重新返回,返回值为val。
例如:
#include <stdio.h>
#include <setjmp.h>
#define MAXLINE 512
jmp_buf jmp_buffer;
void fun2(char buff[])
{
int i = 1;
if( 1 == i )
{
printf("fun2 , longjmp()\n");
longjmp(jmp_buffer,2);
}
}
void fun1(char buff[])
{
printf("fun1 , buff: %s\n",buff);
fun2(buff);
}
int main()
{
char buff[MAXLINE];
int flag,val;
if( (val = setjmp(jmp_buffer)) != 0 )
{
printf("err\n");
}
printf("setjmp:%d\n",val);
while( fgets(buff,MAXLINE,stdin) != NULL )
{
fun1(buff);
}
return 0;
}
注意: 错误返回后的变量值有的是返回原先的状态,有得是内存函数的改变后的值,只是根据变量属性不同会有所改变。如果不想要返回到main函数时数值回滚,则可以将其定义为volatile属性。