UNIX进程的环境

UNIX进程的环境

(本文为读书笔记)

一、atexit函数

按照ANSI C 规定,一个进程可以登记32个函数,这些函数由exit自动调用。所以也称这些函数为终止处理函数(exit handler),用atexit函数来登记他们。

函数原型如下:

#include<stdlib.h>

int atexit(void (*func)(void));          ---------成功返回0,否则非0

调用此函数不需要向它传递任何参数,当exit对他们的调用顺序和他们在atexit函数登记时的顺序相反,登记几次则调用几次。

#include<stdio.h>
#include<stdlib.h>
static void my_exit1(void);
static void my_exit2(void);
int main()
{

if(atexit(my_exit1)!=0)
printf("%s\n","atexit error!");

if(atexit(my_exit1)!=0)
printf("%s\n","atexit error!");

if(atexit(my_exit2)!=0)
printf("%s\n","atexit error!");
printf("%s\n","main run!");
return 0;
}
static void my_exit1(void)
{
printf("%s\n","exit1 handler");

}
static void my_exit2(void)
{
printf("%s\n","exit2 handler");
}

程序运行结果:

此函数的作用(思考):对于全局而言善后工作,文件或数据的操作。等等。

二、程序存储

1)malloc。分配制定字节数的存储区。初始值不确定。

2)calloc。为指定长度的对象分配能容纳其指定个数的存储空间,空间中每一位初始化为0。eg:int * n  分配n个int型的空间。

3)realloc。更改以前分配去的长度。可能发生存储区迁移,新增区初始值未知。

4)alloca。在栈上为当前函数分配存储空间,非堆。但某些系统在函数调用后不能增加栈的长度,所以不支持alloca函数。

注意:对于存储区会发生迁移的函数,不要用指针指向这个区域。

图片来自APUE

大多数实现分配的存储空间比所要求的要稍大一些,额外的空间用来记录管理信息–分配块的长度,只想下一分配块的指针等等。这意味着如果写一个已分配区的尾端,将会改写后一块的管理信息。

三、setjmp和longjmp函数

函数原型:

#include<setjmp.h>

int setjmp(jmp_buf env);         ————直接调用返回0,从longjmp返回则为非0

void longjmp(jmp_buf env, int val);

通过setjmp的返回值来判断是从哪一个longjmp返回来的。如果存在不希望变量因为setjmp函数造成回滚,可以将这个变量申明为volatile属性。说明为全局变量和静态变量的值在执行longjmp时保持不变。

四、fork函数

函数原型:

#include<sys/types.h>

#include<unistd.h>

pid_t fork(void);

fork函数用于一个现存函数调用来创建一个新进程的方法,该函数调用一次返回两次,在父进程中返回值为pid,子进程中返回值为0。函数执行失败返回值为一个非正值。子进程将获得父进程的数据空间,堆和栈的复制品。父子进程并不共享这些存储空间,如果正文段是只读的,则父子进程共享正文段。

代码图不够清晰,可以看APUE第8章。

fork示例程序,代码来自APUE。

运行结果为:

fork程序运行结果

wirte函数是不带缓存的。在fork之前调用write,所以数据写到标准输出一次。但是标准I/O库是带缓存的。如果标准输出连到终端设备,则他是行缓存,否则他是全缓存。当以交互方式运行该程序时,printf输出一次,由‘\n’刷新标准输出缓存。但是当标准输出重新定向到一个文件时,printf输出两次,因为当调用fork时,行数据仍在缓存中,在父进程数据空间复制到子进程数据空间中时该缓存数据也被复制到了子进程中。

 

 

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注