第7章 进程环境

版权声明:转载请声明 https://blog.csdn.net/qq_40732350/article/details/82353280

请移步到这:

http://note.youdao.com/noteshare?id=7896d7e621203ead98bac87831143a84&sub=B28BAAE5F8AF40348692BF1B708FFBB6

7.2 main函数

7.3 进程中止

有8种方式使进程终止(termination),

其中5种为正常终止,它们是:

(1)从main返回;

(2)调用exit:

(3)调用exit或_Exit;

(4)最后一个线程从其启动例程返回(11.5节);

(5)从最后一个线程调用pthread_exit (11.5节),

异常终止有3种方式,它们是:

(6)调用abort (10.17节);

(7)接到一个信号(10.2节);

(8)最后一个线程对取消请求做出响应(11.5节和12.7节)。

1.退出函数

3个退出函数都带一个整型参数,称为终止状态(或退出状态, exit status),大多数UNIX系,统shell都提供检查进程终止状态的方法。

如果

(a)调用这些函数时不带终止状态

(b) main执行了一个无返回值的return语句

(c) main没有声明返回类型为整型,则该进程的终止状态是未定义的。

但是,若main的返回类型是整型,并且main执行到最后一条语句时返回(隐式返回),那么该进程的终止状态是0.

不做任何返回的现象:

2. 函数atexit

用sysconf(_SC_ATEXIT_MAX)可以得到最大值

注意:

内核使程序执行的唯一方法是调用一个exec函数。

进程自愿终止的唯一方法是显式或 ,隐式地(通过调用exit)调用exit或Exit.进程也可非自愿地由一个信号使其终止(图7-21中没有显示),

7.4 命令行参数

7.5 环境表

geten,putenv——》访问特定

第三参数,environ——》访问全部

7.6 c程序的存储空间布局

•历史沿袭至今, C程序一直由下列几部分组成:

正文段。

这是由CPU执行的机器指令部分。通常,正文段是可共享的,所以即使是频繁执行的程序(如文本编辑器、C编译器和shell等)在存储器中也只需有一个副本,另外,正文段常常是只读的,以防止程序由于意外而修改其指令。

初始化数据段。

通常将此段称为数据段,它包含了程序中需明确地赋初值的变量。例如,C程序中任何函数之外的声明:

int maxcount = 99:

使此变量以其初值存放在初始化数据段中。

未初始化数据段。

通常将此段称为bss段,这一名称来源于早期汇编程序一个操作符,意思是“由符号开始的块” (block started by symbol),在程序开始执行之前,内核将此段中的数据初始化为0或空指针。函数外的声明:

long sum [10001];

使此变量存放在非初始化数据段中。

栈。

自动变量以及每次函数调用时所需保存的信息都存放在此段中。每次函数调用时,其返回地址以及调用者的环境信息(如某些机器寄存器的,值)都存放在栈中。然后,最近被调用的函数在栈上为其自动和临时变量分配存储空间。通过以 ,这种方式使用栈, C递归函数可以工作。递归函数每次调用自身时,就用一个新的栈帧,因此一次函数调用实例中的变量集不会影响另一次函数调用实例中的变量。

堆。

通常在堆中进行动态存储分配。由于历史上形成的惯例,堆位于未初始化数据段和栈之间。

7.7 共享库

7.8 存储空间分配

参考:https://blog.csdn.net/david_xtd/article/details/7311204

扩充(或缩小)进程的堆——>>通常用sbrk(2)系统调用实现。

大多数实现所分配的存储空间比所要求的要稍大一些,额外的空间用来记录管理信息-分配块的长度、指向下一个分配块的指针等。

这就意味着,如果超过一个已分配区的尾端或者在已,分配区起始位置之前进行写操作,则会改写另一块的管理记录信息。这种类型的错误是灾难性的,但是因为这种错误不会很快就暴露出来,所以也就很难发现。

在动态分配的缓冲区前或后进行写操作,破坏的可能不仅仅是该区的管理记录信息。在动态分配的缓冲区前后的存储空间很可能用于其他动态分配的对象。这些对象与破坏它们的代码可能无关,这造成寻求信息破坏的源头更加困难。

其他可能产生的致命性的错误是:

1.释放一个已经释放了的块

2.调用free时所用的指针不是3个alloc函数的返回值等。

如若一个进程调用malloc函数,但却忘记调用free函数,那么,该进程占用的存储空间就会连续增加,这被称为泄漏(leakage),如果不调用free函数释放不再使用的空间,那么进程地址空间长度就会慢慢增加,直至不再有空闲空间。此时,由于过度的换页开销,会造成性能下降。

解决上面的问题:

因为存储空间分配出错很难跟踪,所以某些系统提供了这些函数的另一种实现版本。

1.每次调用这3个分配函数中的任意一个或free时,它们都进行附加的检错。

2.在调用连接编辑器时指定,一个专用库,在程序中就可使用这种版本的函数。

3.此外还有公共可用的资源,在对其进行编译时使用一个特殊标志就会使附加的运行时检查生效。

这些函数要另外下载

7.9 环境变量

输出环境变量:

设置环境变量:

我们可能希望改变现有变量的值,或者是,增加新的环境变量。

我们说改变的环境变量,只是当前进程及其后生成和调用的任何子进程的环境

我们的改变是不能影响父进程的环境,这通常是一个shell进程。

尽管如此,修改环境表的"能力仍然是很有用的。)遗憾的是,并不是所有系统都支持这种能力。图7-8列出了由不同的标准,及实现支持的各种函数。

修改环境表的原理

7.10 函数setjmp和longjmp

参考这个博客啥都了解:

https://blog.csdn.net/smstong/article/details/50728022

非局部跳转语句---setjmp和longjmp函数。

这不是由普通C语言goto,goto语句只能在一个函数内实施的跳转

而setjmp和longjmp是在栈上跳过若干调用帧,返回到当前函数调用路径上的某一个函数中。

自己总结:

这个机制就是解决,在多层嵌套函数中,当发生异常后,函数要先一层一层返回,最后到main函数中去执行出错,这样效率太低。

于是改为直接跳转到main函数的栈中去执行,这样更快

注意:

全局变量、静态变量和易失变量不受优化的影响,在ongimp之后,它们的值是最近所呈现的值。在某个系统的setjmp(3)手册页上说明,存放在存储器中的变量将具有lngjmp时的值,而在CPU和浮点寄存器中的变量则恢复为调用setimp时的值。这确实就是运行图7-13程,序时所观察到的值。

不进行优化时,所有这5个变量都存放在存储器中(即忽略了对regival变量的register存储类说明),

而进行了优化后, autoval和reqival都存放在寄存器中(即使 autoval并未说明为register), volatile变量则仍存放在存储器中。

总结:

通过这一实例我们可以理解到,如果要编写一个使用非局部跳转的可移植程序,则必须使用volatile属性。从而让一些变量不要优化,因为有些变量我们需要得到改变后的值,而不是优化后的值。但是从一个系统移植到另一个系统,其他任何事情都可能改变。

没读懂?

7.11 函数getrlimit和setrlimit

结构体在这

猜你喜欢

转载自blog.csdn.net/qq_40732350/article/details/82353280