第七章 进程环境

            第七章    进程环境

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


一个进程的终止也分为好几种情况:    
    首先正常终止:
        1、 从 main 返回            2、调用 exit
        3、 调用 _exit或 _Exit        4、最后一个线程从其启动例程返回
        5、 最后一个线程调用 pthread_exit
    其次非正常终止:
        1、调用 abort            2、接到一个信号
        3、最后一个线程对取消请求作出响应

以上提到的启动例程若是用C语言表示(实际上该例程常用汇编编写)就是如此:
    exit( main( argc , argv ) );
    exit总是执行一个标准 I/O 库的清理关闭操作:
        对所有打开流调用 fclose 操作

函数    atexit
    登记终止处理程序(可有多个)  见本章文件夹下程序 atexit.c
     最后调用这些程序的顺序与它们登记时候的顺序相反。同一函数若登记多次,也会被调用多次。


环境表:
    之前在学到进程时候,我也曾想父子进程是如何进行变量传递的呢? 后来通过 exec(3) 查看manpage的时候发现有个 extern char **environ;
        即一个指向字符串数组的指针指向一张 环境表。
    函数    getenv 可以得到某个环境变量的值
        setenv    将name值设置为value, 若name已经存在:
                1、 若第三个参数为0, 则不删除现有定义,即无操作
                2、     非0, 则删除原有定义
        putenv    设置或改变环境变量的值(若原来就存在,那么删除原来的)
        unsetenv、clearenv
    如果要修改一个现有的name:
        A、如果新的name长度少于或等于现有的value的长度,则只要将新字符串复制到原字符串所用的空间中
        B、如果新value长度大于原长度,则必须用malloc为新字符串分配空间,然后将新字符串复制到该空间,接着使环境表中针对name的指针指向新分配区。
    如果要新增一个name,首先要用malloc为 name=value 分配空间,并将其复制进此空间:
        A、如果是第一次增加一个新name,则必须调用malloc为新的指针表分配空间。接着将原来的环境表复制到新的分配区,并将指向新 name=value 字符串的指针存放在指针
            表表尾,并将一个空指针放在其后面。最后使 environ 指向新的指针表。
        B、若不是第一次,只需调用 realloc 。记得最后放一个空指针。


C程序的存储空间和布局:
    C程序一直由以下几个部分组成:
        1、 正文段
            这是由CPU执行的机器指令部分。通常是可以共享的,所以即使是频繁执行的程序(文本编辑器,编译器,和shell等)在存储器中也只需一个副本。常常是只读的,
                以防止程序由于意外而被修改。
        2、 初始化数据段
            包含了程序中需要明确的赋初值的变量(除函数声明外),例如  int a=999;
                使此变量以其初值存放在初始化数据段中
        3、 未初始化数据段
            常称为 bss 段,意思是 由符号开始的块(除函数声明外), 即  int a[100];    
        4、
            自动变量以及每次函数调用时所需保存的信息都存放在此段中。    每次函数调用时,其返回地址以及调用者的环境信息(如寄存器的值)都存放在栈中。
                然后,最近被调用的函数在栈上为其自动和临时变量分配存储空间。 因此可以实现递归。
        5、
            常在堆中进行动态存储分配

在使用共享库后,可显著减少每个可执行文件的长度,但增加了一些运行时开销。

函数    realloc
    若要扩充一个数组的长度,如果该存储区有足够的空间可供扩充,则可在原存储区位置上向高地址方向扩充,无需移动任何数据,并返回传入的指针。
        如果该区没有足够的空间,则realloc分配另一个足够大的存储区,将现在的内容复制到新的存储区,然后释放原存储区,返回新指针
    与之相应的函数 malloc cmalloc
    这些都是由系统调用 sbrk实现的


函数    setjmp、 longjmp
        goto语句是不能跨函数的,而这两个函数能实现这种类型跳转功能
        这不是由普通的C语言 goto 语句在一个函数内实施的跳转,而 是在栈上跳过若干调用帧,返回到当前函数调用路径上的某一个函数中。
    在希望返回到的位置调用setjmp, 其参数是一个特殊类型 jmp_buf
        这一参数类型是某种形式的数组,其中存放在调用longjmp时能用来回复栈状态的所有信息。因为需要在另一个函数中引用env变量(即该参数),所以常设为全局变量。
        这一参数里存了什么内容书上并未讲明
    在检查到出错时,调用longjmp函数,第一个即是与setjmp中参数相同的参数(全局变量),第二个变量是非0的值,它将成为setjmp处返回的值。
        使用第二个参数原因是对于一个setjmp可以有多个longjmp,即在不同地方出错返回到设setjmp的地方后,可以根据返回值来判断是哪里出错了。
    既然可以如此使用,那么当调用longjmp返回到setjmp处后,setjmp之前设置的变量能否恢复到setjmp之前的值呢?
        根据书上实例,答案是  看情况。。。
        会根据 自动变量,寄存器变量,全局变量,静态变量这些变量类型得到不同的结果。
        此处比较复杂,等到用到的时候再回来看             P174


函数    getrlimit、 setrlimit
    每个 进程都有一组资源限制,其中一些可以使用这两个函数进行查询和修改。
    更改资源时候,要尊需3个规则
        1、任何一个进程都可以将一个软件限制值更改为小于或等于其硬件限制值    
        2、任何一个进程都可以降低其硬件限制值,但它必须大于或等于其软件限制值。这种降低,对普通用户是不可逆的

        3、只有root能提高硬件限制值


    在看习题发现这一题:
        在有些Unix系统实现中执行程序时访问不到其数据段的 0 单元,这是一种有意的安排, 是为什么?
            答案是:当C程序解引用一个空指针出错时,执行该程序的进程将终止。可以利用这种方法终止进程。



话说学了这章有点懵。 一些东西你说学过了确实学过了,可再回顾就觉得陌生。可能是练习的比较少的,就像理解了一个成语的意思,不去用,往往就遗忘了。
知识点也比较细碎。
刚发现原来有课后习题答案的。。。看来这课后习题也要多做做了
最近实在是乱,一大堆期末叠在一起,笔记本win系统又进不去了,.net作业也不好做,很多资料打不开,一直蓝屏,很缺钙!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值