编译可参考:
http://blog.chinaunix.net/u2/88926/showart_2034093.html
Chapter 3.
3.1 关于buffered i/o和unbuffered i/o区别
http://hi.baidu.com/oxbat/blog/item/91fefdc46402bfaa8326ac57.html明确一个关系,那就是,buffered I/O库函数(fread, fwrite等,用户空间) <----call---> unbuffered I/O系统调用(read,write等,内核空间)<-------> 读写磁盘.
使用库函数的效率是高于使用系统调用的.buffered I/O就是通过尽可能的少使用系统调用来提高效率的.以前总觉得系统调用的效率高,我的观点错误了,呵呵。
一般情况下,标准输入输出两个流是行缓存,重新定向到普通文件时,它们就变成是全缓存的。参照apue ch5.
Chapter 7.Process Environment
7.2 可执行程序的执行过程:
main()函数执行前,首先执行exec()这个特定的例程,这是由gcc链接器决定的。
7.3 进程终止:
7.3.1 正常终止:
7.3.1.1. Return from main
7.3.1.2 Calling exit
7.3.1.3 Calling _exit or _Exit
7.3.1.4 Return of the last thread from its start routine (Section 11.5)
7.3.1.5 Calling pthread_exit (Section 11.5) from the last thread
7.3.2 非正常终止:
7.3.2.1 Calling abort (Section 10.17)
7.3.2.2 Receipt of a signal (Section 10.2)
7.3.2.3 Response of the last thread to a cancellation request (Sections 11.5 and 12.7)
7.3.3 三种exit()函数的不同点:
_exit and _Exit立即返回kernel, and exit做一定清除工作再返回kernel.
内核使程序执行的唯一方法是调用一个exec函数。进程自愿终止的唯一方法是显式或隐式地(调用exit)调用_exit。进程也可非自愿地由一个信号使其终止.
程序退出的方法很多,信号,exit(),需要与程序退出方式无关的方法来进行程序退出时的必要处理。方法就
是用atexit()函数来注册程序正常终止时要被调用的函数。
7.3.4环境表:
每个程序都接收到一张环境表。与参数表一样,环境表也是一个字符指针数组,其中每个指针包含一个以n u l l结束的字符串的地址。全局变量e n v i r o n则包含了该指针数组的地址。
7.3.5 c程序内存分布:
正文段应该就是代码段。
size(1)命令查看正文段、数据段(初始化的数据)和bss段的长度(单位:字节)
7.3.6 共享库
可以减少可执行文件长度。便于版本更新。
7.3.7 存储器分配:malloc等等
7.3.8 环境变量:
7.3.9 setjmp和longjmp函数
非局部跳转——setjmp和longjmp函数。非局部表示这不是在一个函数内的普通的C语言goto语句,而是在栈上跳过若干调用帧,返回到当前函数调用路径上的一个函数中.
以两个参数调用longjmp函数。第一个就是在调用setjmp时所用的env;第二个val,是个非0值,它成为从setjmp处返回的值。使用第二个参数的原因是对于一个setjmp可以有多个longjmp。例如,可以在cmd_add中以val为1调用
longjmp,也可在get_token中以val为2调用longjmp。在main函数中,setjmp的返回值就会是1或2,通过测试返回值就可判断是从cmd_add还是从get_token来的longjmp。
注意调用longjmp后,函数调用栈空间的变化。
注意:setjmp和longjmp对于从c++并非很好支持。
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子: 1). 并行设备的硬件寄存器(如:状态寄存器) 2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) 3). 多线程应用中被几个任务共享的变量 讲解volatile的好文章:
http://blog.21ic.com/user1/2949/archives/2007/35599.html注意:程序编译优化后,自动变量的值的读取位置可能变为寄存器了,可能与内存中的不同。
Chapter 8. Process Control
8.2 进程id是唯一的,可复用的,但会稍等片刻,以防马上使用引起错误。
8.2.1 进程ID 0是调度进程,常常被称为交换进程( swapper )。该进程并不执行任何磁盘上的程序—它是内核的一部分,因此也被称为系统进程.进程ID 1通常是init进程,在自举过程结束时由内核调用。程序文件是/sbin/init。
init进程决不会终止。
8.3fork 函数
8.3.1 父子进程和文件描述符,在fork之后处理文件描述符有两种常见的情况:
(1) 父进程等待子进程完成。在这种情况下,父进程无需对其描述符做任何处理。当子进程终止后,它曾进行过读、写操作的任一共享描述符的文件位移量已做了相应更新。
(2) 父、子进程各自执行不同的程序段。在这种情况下,在fork之后,父、子进程各自关闭它们不需使用的文件描述符,并且不干扰对方使用的文件描述符。这种方法是网络服务进程中经常使用的。
8.3.2 fork有两种用法:
(1)一个父进程希望复制自己,使父、子进程同时执行不同的代码段。这在网络服务进程中是常见的——父进程等待委托者的服务请求。当这种请求到达时,父进程调用fork,使子进程处理此请求。父进程则继续等待下一个服务请求。
(2) 一个进程要执行一个不同的程序。这对shell是常见的情况。在这种情况下,子进程在从fork返回后立即调用exec (我们将在8.9节说明exec )。
注意vfork和fork的区别。
8.3.3 exit函数的用法,以及_exit用法:
在说明fork函数时,一定是一个父进程生成一个子进程。上面又说明了子进程将其终止状态返回给父进程。但是如果父进程在子进程之前终止,则将如何呢?其回答是对于其父进程已经终止的所有进程,它们的父进程都改变为i n i t进程。我们称这些进程由init进程领养。其操作过程大致是:在一个进程终止时,内核逐个检查所有活动进程,以判断它是否是正要终止的进程的子进程,如果是,则该进程的父进程I D就更改为1(init进程的ID )。这种处理方法保证了每个进程有一个父进程。一个由init进程领养的进程终止时会发生什么?
Chapter 10. Signals
信号是典型的异步处理事件. Signals occur at what appear to be random times to the process. The process can't simply test a variable (such as errno) to see whether a signal has occurred; instead, the process has to tell the kernel "if and when this signal occurs, do the following.",学习思想。
disposition of the signal
信号处理,我们可以告诉内核作以下三件事情或若干:
Ignore the signal;
Catch the signal. To do this, we tell the kernel to call a function of ours whenever the signal occurs.
****************习题解答*******************
7.1 返回值是随机的,与exit(n)的n值相同。
7.10 val != 0时候 *ptr值随机。
阅读(837) | 评论(0) | 转发(0) |