APUE 第七章 进程的运行环境
来源:互联网 发布:蚂蜂窝app无网络 编辑:程序博客网 时间:2024/05/20 06:28
APUE第七章主要分享了进程的运行环境。主要内容包括:
1、main函数
在这节里面主要说明了在我们平常利用的main函数是如何被调用的。其实从程序开发人员的角度会考虑这样一个问题,编译后 的程序为什么会运行?为什么要有main函数等等。main函数是不是程序最开始运行的地方,等等。
其实当一个C程序在运行前,系统会做很多的初始化工作,然后再调用exec函数来运行C程序。
2、进程的终止
- 进程的终止方式有8种:
- 其中正常终止有5种:
- return from main
- 调用exit函数
- 调用_exit或者_Exit函数
- return of the last thread from its start routine
- call pthread_exit from the last thread
异常终止有3种:
- 调用abort
- receipt of a signal(收到信号)
- response of the last thread to a cancellation request
接下来有三个exit函数:
#include<stdlib.h>
void exit(int status);
void _Exit(int status);
#include<unistd.h>
void _exit(int status);
其中_Exit和_exit函数会理解返回到kernel;而exit函数会做一些清理工作,比如调用fclose关闭文件等,将未写入的文件flush掉等,然后会返回kernel。
这三个函数都有一个int的参数,称为exit status。大多数的shell可以检测进程退出时的状态。如果在main函数中没有调用return、exit或者return了但没有指定return的值,那么进程的exit status是不确定的。但在C99里面,进程的退出状态为0.
eg:
#include<stdio.h>
main()
{
printf("hello, world/n");
}
编译,链接,运行程序。
$ ./a.out
hello, world
$echo $? //用于输出进程的退出状态
13//可以看到退出状态是13,其实是printf函数的返回值
而如果指定是C99方式的话,即
$ cc -std=c99 hello.c //指明是C99
hello.c:4 warning: return type defaults to int
$ ./a.out
hello, world
$echo $?
0
可以看到C99标准下退出状态是0
曾经看到一道笔试题,说main函数在调用结束的时候会不会有什么动作,大概是这个意思吧。其实就是考的如下函数
#include<stdlib.h>
int atexit(void (*func) (void));
在ISO C中一个进程可以注册至多32个函数,这些函数是在进程exit的时候调用的。同时这些函数调用的顺序和他们注册的顺序相反,有点类似C++中构造函数一样。
下面这张图展示了一个C程序的如何开始和结束的:
从上图可知,kernel调用exec函数族来运行C程序,在C程序运行过程中会调用其他的函数,然后C程序可能会调用exit系列或者return(其实是间接调用exit)来结束自己的运行。可以看到,在调用exit函数时,程序不会理解返回到kernel中,而是做了一系列的清理工作,然后调用_exit或者_Exit函数返回kernel的。
3、命令行参数
在调用exec函数族的时候可以传递给进程一系列的参数。
4、环境列表
环境列表主要是在全局变量char **environ中存储,形式是name=value,可以从下图看出:
一般来说,获取环境变量不是通过直接操作environ变量来进行的,而是通过调用getenv和setenv函数来进行的。
5、C程序在内存中的布局
6、shared library
库文件的使用大大减少了可执行文件的大小,同时当库内部函数的具体实现改变时,只要接口不改变,不会影响库的使用。库文件一个缺点是当系统第一次调用库文件时开销会大一点。
7、内存分配
这里说的内存主要是指的是堆空间的分配。堆空间在使用的时候需要特别注意,需要开发人员自己申请,同时也需要自己释放不再需要的空间,如果不正确释放堆空间,那么会照成memory leak,即内存泄漏。
堆空间分配的函数主要有:
#include<stdlib.h>
void *malloc(size_t size);
//malloc用来分配size大小的堆空间,同时分配空间的初始值是不确定的!!
void *calloc(size_t nobj, size_t size);
//calloc用来分配nobj个大小为size的空间,即分配nobj*size大小的空间,但不同于malloc的是calloc分配的空间是初始化过的!
void *realloc(void *ptr, size_t newsize);
//realloc用来增长或者减少之前分配的空间。需要注意的是ptr指向的空间必须是通过malloc或者calloc分配的空间!!如果ptr为NULL,那么realloc与malloc类似,用来分配newsize大小的空间。
//return NULL on error. non-null is OK
void free(void *ptr);
//释放堆空间。其中ptr必须是malloc、calloc或者realloc调用后的返回值,即必须是动态内存的分配才可以使用free释放。
可以利用lint和valgrind等检测工具来检测程序中的隐蔽bug,将这两个工具结合起来很是给力~
8、环境变量
从前面的介绍中可以看到,环境变量的形式是name=value。一般来说不是直接操作environ来进行获取或设置,而是通过getenv或者setenv函数来获取和操作的。
#include<stdlib.h>
char *getenv(const char *name);
//通过name来获得对应的value。
我们可以改变当前进程和他子进程的运行环境,但是不能改变当前进程父进程的运行环境。
9、setjmp和longjmp函数
在C语言中,goto语句一般是不提倡使用的,但如果研究一些源代码会发现,其实很多代码里面都使用的goto。但是goto语句有一个不足的地方就是他不能跳出函数的范围,只能在一个函数内部进行。标准库提供了setjmp和longjmp函数来结合使用,可以实现长跳转。
一般来说setjmp和longjmp函数用于一些出错处理,其他方面用的不多,很多地方都建议尽量少使用。
可参考《APUE》和《c专家编程》
10、getrlimit和setrlimit函数
每一个进程都有一系列资源的限制,例如进程最多可以打开的文件数、进程堆栈的大小等。这些limit可以通过getrlimit和setrlimit函数来进行获取和设置。
#include<sys/resource.h>
int getrlimit(int resource, struct rlimit *rlptr);
int setrlimit(int resource, const struct rlimit *rlptr);
//return 0 if ok; nonzero on error
其中rlimit是这样一个结构:
struct rlimit
{
rlim_t rlim_cur;//soft limit: 表示当前的limit值
rlim_t rlim_max;//hard limit:表示rlim_cur的最大值
};
一个进程有如下操作:
- 可以改变soft limit,soft limit必须要小于等于hard limit
- 可以改变hard limit,但必须要保证hard limit大于等于soft limit
- 只有超级用户可以改变hard limit
如果某个limit是没有限制的话,那么会被指定为常量:RLIM_INFINITY
下图是一些常见的limit常量和他们的具体含义:
其中在调试程序时用到的一个是core的大小,一般来说可能系统设置core的大小是0,即当程序异常退出时不产生core,这对于调试来说不太实用,因此一般需要调整该值。在bash中,有这样一个命令:ulimit可以改变core文件的大小。
一般是通过:
ulimit -c unlimited来使得core文件的大小不受限制。当然也有其他的选项。
上面大概就是APUE第七章进程运行环境的一个总结,有很多细节需要在设计中深入考虑。
- APUE 第七章 进程的运行环境
- [APUE]第七章 进程环境
- APUE第七章 进程环境
- APUE 第七章 进程环境
- APUE学习笔记:第七章 进程环境
- apue第七章 进程环境 笔记
- APUE读书笔记-第七章 进程环境
- 《APUE》笔记-第七章-进程环境
- APUE笔记---第七章 进程环境
- 《APUE》读书笔记—第七章进程环境
- old《APUE 2e》学习笔记 第七章 进程环境
- APUE学习笔记——第七章 进程环境
- apue学习笔记(第七章 进程环境)
- apue:UNIX进程的环境
- APUE学习笔记5——第七章——进程环境
- 第七章 进程环境
- 第七章 进程环境
- 第七章进程环境
- SQL 安装 程序配置服务器失败
- Java2D+3D游戏王(Yo-Gi-Oh!)开发日志5 —— 决斗器V0.3.0
- Sql事务实例
- 第十六讲:多重继承
- 操作目录(文件和流)
- APUE 第七章 进程的运行环境
- Ruminations on C++ code snipets
- 修改MFC标题栏上的图标和修改MFC窗口标题
- 第十七讲:基类与派生类的转换
- 用Carbide C++ UI Designer做UI的爽与不爽
- 操作文件 (File和FileInfo类)
- 盈通GTS 450游戏高手评测
- RTMP协议中的AMF0格式定义
- nike sai