chapter 7之进程管理

来源:互联网 发布:视频交友软件聊天 编辑:程序博客网 时间:2024/05/19 12:28

C程序总是从main函数开始执行,main函数的原型是:

int main(int argc, char *agrv[]);

当内核执行C程序时(使用一个exec函数),在调用main函数之前,先调用一个特殊的启动例程。可执行程序文件将此启动例程指定为程序的起始地址——这是由连接编辑器设置的,而连接编辑器则由C编译器(通常是cc)调用。启动例程从内核取得命令行参数和环境变量值,然后为按照上述方式调用main函数做好安排。

在apue书中,给出了一个实例7-1,从这个例子以及课后习题7.2,有以下几个知识点需要注意:

1.printf的返回值(输出的字符数)变成了main函数的返回值,注意,并不是所有的系统都会出现这种状况。对于Linux ubuntu 3.0.0-16-generic #29-Ubuntu SMP Tue Feb 14 12:49:42 UTC 2012 i686 i686 i386 GNU/Linux(利用uname -a命令查询与当前主机和操作系统有关的信息),来说,返回值正是printf的字符数。

2.在命令行中输入echo #?能够打印上一条命令的终止状态。

3.命令:gcc -std=c99 hello.c 启用gcc's 1999 ISO C扩展,对于我的系统,启用后,会像apue书中提到的显示一条提示信息。打印终止状态,发现返回的终止状态是空。

书中说,main函数返回的任意整型值与用该值调用exit是等价的,于是在main函数中

exit(0);

等价于

return(0);

但是,对于我的操作系统,利用exit调用0返回时,编译时,有如下警告(这里使用实例7-3进行测试):

l7-3.c: 在函数‘main’中:
l7-3.c:9:3: 警告: 隐式声明与内建函数‘exit’不兼容 [默认启用]实例

对于实例7-2,有个知识点要注意,这个程序说明如何使用atexit函数,而atexit的原型如下:

#include <stdlib.h>

int atexit(void (*func)(void));                                                    //返回值:若成功则返回0,若出错则返回非0值

atexit的参数是一个函数地址,当调用此函数时,无需向它传任何参数,也不期望它返回一个值。exit调用这些函数的顺序与登记它们的顺序相反。同一个函数如若登记多次,也会被调用多次。

注意,函数指针这个知识点,具体的学习介绍将专门放到一篇文章中。

下面说说环境表这个知识点,环境表是一个字符指针数组(对于字符指针数组和指向指针的指针之间的联系和区别,要好好温习下),全局变量environ包含了该指针数组的地址 。按照惯例,环境由name=value这样的字符串组成。

C语言一直由下面几部分组成:正文段、初始化数据段、非初始化数据段、堆、栈。利用size命令可以查看正文段、数据段、bss(非初始化数据段)的长度(单位:字节)。利用size命令得到结果的第四列和第五列分别以十进制和十六进制表示三个段的总长度。

共享库使得可执行文件中不再需要包含公用的库例程,而只需要在所有进程都可以引用的存储区维护这种库例程的一个副本。程序第一次执行,或者第一次调用某个库函数时,用动态链接方法将程序与共享库函数相链接。这减少了每个可执行文件的长度,但是增加了一些运行时间开销。这种时间开销发生在程序第一次被执行时,或者每个共享库函数第一次被调用时。共享库函数的另一个优点是可以用库函数的新版本代替老版本,而无需对该库的程序重新连接编辑。(假定参数数目和类型都没有改变。)

在gcc编译命令中,利用-static参数,可以阻止gcc使用共享库。在我的系统中,得到下面的结果:

goku@ubuntu:~/apue/chapter7$ cc -static l7-1.c                                                            阻止gcc使用共享库
goku@ubuntu:~/apue/chapter7$ ls -l a.out
-rwxrwxr-x 1 goku goku 652622 2012-03-16 22:08 a.out
goku@ubuntu:~/apue/chapter7$ size a.out
   text       data        bss        dec        hex    filename
 581289       2056       7048     590393      90239    a.out


goku@ubuntu:~/apue/chapter7$ gcc l7-1.c                                                                       gcc默认使用共享库
goku@ubuntu:~/apue/chapter7$ ls -l a.out
-rwxrwxr-x 1 goku goku 7158 2012-03-16 22:12 a.out
goku@ubuntu:~/apue/chapter7$ size a.out
   text       data        bss        dec        hex    filename
   1132        256          8       1396        574    a.out


两者相比,发现可执行文件的正文段和数据段的长度,明显减少。

运行实例7-6,得到的结果,跟apue所说的相同,注意这里的运行命令,优化编译命令,使用了参数-O。全局、静态、易失变量不受优化的影响。易失变量使用关键字volatile标记,用volatile关键字定义变量,相当于告诉编译器,这个变量的值会随时发生变化,每次使用时都需要去内存里重新读取它的值,并不要随意针对它作优化。

自动变量有一个潜在问题,声明自动变量的函数已经返回后,不能再引用这些自动变量了 。

进程的资源限制,通常是在系统初始化时由进程0建立的,然后由每个后续进程继承。每种实现都可以用自己的方法对各种限制做出调整。

对于最后一个资源限制的例子,注意ISO C中宏的字符串创建运算法(#),doit(RLIMIT_CORE)将由预处理程序扩展为:pr_limits("RLIMIT_CORE",RLIMIT_CORE)。输入书中的例子,程序编译时出现如下问题:

goku@ubuntu:~/apue/chapter7$ gcc l7-8.c
l7-8.c:55:1: 警告: 与‘pr_limits’类型冲突 [默认启用]
l7-8.c:56:1: 错误: 对‘pr_limits’的静态声明出现在非静态声明之后
l7-8.c:19:2: 附注: ‘pr_limits’的上一个隐式声明在此

这种错误是因为声明pr_limit时少了一个s,跟其他部分不匹配。

接下来,谈谈本章的课后习题,课后习题很重要,还是要看看。