Unix环境高级编程学习笔记(四) 进程环境

C程序的内存布局

首先看下面这个图,有个大致的概念:
Unix环境高级编程学习笔记(四) 进程环境_第1张图片
每一个C程序都有自己独立的地址空间,它们包含五个部分:

1. 代码段(Text segment)

存放程序的执行代码,即使在多进程的环境下,它也只有一份。

2. 初始化数据段(Initialized data segment)

例如初始化的全局变量
int maxcount = 99;

3. 未初始化的数据段(Uninitialized data segment)

例如初始化的全局变量,这些变量的值将由kernel初始化为0
long sum[1000];

4. 栈(stack)

在程序的执行过程中存储函数调用信息的动态数据结构。

5. 堆(heap)

堆用于动态分配和释放程序所使用的对象。

需要注意的是,这是在内存中的布局,事实上,只有代码段和初始化数据段的内容才需要被真正存储在程序文件中。

环境表(Environment List)

在unix中,每一个进程都有自己的环境变量的集合,它们被称之为环境变量时因为表中的默认变量常常被用于配置目的。在前面的文章段落中,我们讨论了C程序的内存布局,可以看见环境表通常位于进程地址空间的高地址处,正好在栈的上面。让我们详细看一下环境表的结构:
Unix环境高级编程学习笔记(四) 进程环境_第2张图片
我们通常会有一个全局指针指向该表的首地址,它的声明如下:
extern char **environ;

可以看出该表实际上是一个指针数组,每一个元素指向了一个环境变量的键值对字符串,最后一个元素后面跟着一个空指针用于标识表的结束。一般来说,默认的环境变量都是以全大写形式的。如非必要,我们不应该自己通过environ指针去访问该表,POSIX自会为我们提供合适的函数去访问它们:
char *getenv(const char *name);
int putenv(char *str);
int setenv(const char *name, const char *value,
int rewrite);
int unsetenv(const char *name);

进程的中止方式

进程的正常中止方式有以下5种:
1.   调用exit库函数。
该函数通常在正常关闭前会做些清扫工作(例如关闭打开的流),之后再返回kernel。

1.   通过main函数的返回值。

实际上,其内在的实现方式相当于:exit(main(argc, argv));

3.   调用 _exit函数 或 _Exit函数。

       该种方式直接返回kernel,不做任何的清扫工作。

只不过前者属于系统调用,后者属于库函数。

4.   进程的最后一个线程结束返回。

5.   进程的最后一个线程调用 pthread_exit函数。

以下是进程的非正常中止方式:

6.  调用abort函数。

7.  接收到一个信号。

8.  对最后一个线程的cancellation request进行响应。


有时候,我们希望在进程结束时,能够做一些额外的操作,例如资源回收等,我们可以通过atexit函数进行注册,其声明如下:
int atexit(void (*func)(void));

每个进程可以利用这个函数注册至少32个函数(根据实现不同而不同),这些被注册的函数将被exit函数自动调用。

exit 函数会首先调用这些注册了的函数,然后关闭所有打开了的流,最后才返回kernel。

如果我们调用了exec系列的函数,那么,任何注册了的结束处理函数都将被清除。

你可能感兴趣的:(数据结构,编程,工作,list,unix,存储)