这些日子学习了一下APUE(Advanced Programming in the UNIX,UNIX环境高级编程)。这是一本公认的好书,它详细的讲解200多个函数、提出并解决各种可能存在的问题,这绝对是UNIX程序员居家旅行必备宝典。对于初学者来说它讲得太细太繁杂了。学习完本书后,总体的对它有了点认识,并懂得了使用里面常用的函数。下面是简单的对本书重要的章节给个大体的介绍。

本书印象
本书覆盖了UNIX上数百个系统调用及函数,但是实际上大多数的内容集中在I/O和进程两大方面上。这两方面的内容大概也是用得最广的吧。I/O方面的内容包括了不带缓存的I/O、标准I/O库、终端I/O、高级I/O。进程方面的内容包括UNIX进程的环境、进程控制、信号、进程间通信、守护进程。
终端I/O、数据库函数库、打印机通信、调制解调器、伪终端这些章节感觉不重要,所以没看。进程关系这一章好像也不重要,只有编写精灵进程会涉及到该章的部分知识。其他章节应该都是很重要。

原子操作
只要涉及到多个进程共享资源,原子操作的概念就变成非常重要。
原子操作(atomic operation)指的是由多步组成的操作。如果该操作原子地执行,则或者执行完所有步,或者一步也不执行,不可能只执行所有步的一个子集。
竞态条件(race condition):当多个进程都企图对共享数据进行某种处理,而最后结果又取决于进程运行的顺序时,则我们认为发生了竞态条件。
与之相关的有一个概念,叫时间窗口,它就是竞态条件下发生的。时间窗口大概就是说进程某一个操作与其下一个操作本来应该是连续执行,但是因为进程的切换,导致操作的不连续,导致共享资源被修改,导致程序运行偏离预期。书中10.4节介绍了早期的信号及一些经典的处理案例,这些案例都是由于时间窗口的存在而暗藏隐患。

出错处理
UNIX函数出错,通常返回一负值,并把全局变量errno设置为具有特定信息的值。
<errno.h>定义了errno以及可以赋予它的各种常数。对于errno应当知道两条规则:
1. 如果没有出错,其值不会被一个例程清除。因此,仅当函数的返回值指明出错时,才检验其值。
2. 任一函数都不会将errno值设为0,<errno.h>中定义的所有常数都不为0。

由于每个进程只有一个errno变量,一个通用的规则是,当在信号处理程序中调用库函数或系统调用时,应当在其前保存errno,然后在其后恢复。

I/O效率
1. 对于不带缓存的I/O,当缓存长度等于文件系统的块长时,读操作的时间是最小;缓存长度小于块长,读操作时间增多;大于块长,也不会提高读操作的效率。
2. 标准I/O可以使用户不必像文件I/O那样担心如何选择正确的缓存长度。标准I/O并不比文件I/O慢很多。5.8讲标准I/O的效率。
3. 比起多次read和write,readv和writev更好。12.7讲readv和writev。
4. mmap/memcpy方式比read/write方式效率高,见12.9。

标准I/O
标准I/O可以使用户不必像文件I/O那样考虑缓存及最佳I/O长度的选择。它提供缓存,目的是尽可能少的减少使用read和write的数量。它有三种类型的缓存:全缓存、行缓存和不带缓存。但是标准I/O缓存也是产生很多问题,引起很多混淆的一个领域。
中文版的P142讲了一个很有意思的例子,由于fork的实现方式和IO缓存导致在终端和文件中输出结果的不同。

高级I/O
非阻塞I/O是调用不会永远阻塞的I/O操作,如果操作不能完成,则立即出错返回。
记录锁(record locking)的功能:一个进程正在读或修改文件的某个部分时,可以阻塞其他进程修改同一文件区。
程序12-5讲了一个有趣的例子,让精灵进程阻止其多份副本同时运行,原理是这样的:精灵进程把它们的进程ID写道一个各自专有的PID文件上,通过对这个文件加写锁来保证只有一个副本在运行。
I/O多路转接: select 和 poll,网络编程用得多。
readv和writev函数用于在一个函数调用中读、写多个非连续缓存。
readn和writen读、写指定的N字节数据,并处理返回值小于要求值得情况。
存储映射I/O mmap使一个磁盘文件与存储空间中的一个缓存相映射。当从缓存中取数据,就相当于读文件中的相应字节,类似的,将数据存入缓存,则相应字节就自动地写入文件。

stat函数
第4章详细介绍了stat结构中的每一个成员。包括3个函数,stat、fstat、lstat函数。这使得我们对UNIX文件的各个属性都有所了解。对文件的所有属性以及对文件进行操作的所有函数都有完整的了解对各种UNIX程序设计都非常重要。

非局部转移
setjmp和longjmp函数这两个函数用于执行跨越函数的跳转功能。
用于信号处理程序中做非局部转移时应用sigsetjmp和siglongjmp函数。

进程
特殊进程:进程ID为0的是调度进程,为1的是init进程。
僵死进程:一个已经终止、但是其父进程尚未对其进行善后处理(获取终止子进程的有关信息、释放它仍占用的资源)的进程称为僵死进程。
孤儿进程:父进程已经终止的进程。init进程会领养这些进程。
精灵进程:长生存期,系统引导装入时启动,关闭时终止,后台运行。

fork函数创建新进程。子进程是父进程的复制品(如果正文段是只读的,则父、子进程共享正文段)。现在很多实现并不做一个父进程数据段和堆的完全拷贝,而是使用了在写时复制(Copy-On-Write,COW)技术。
vfork用于创建一个用来exec一个新程序的新进程,所以它不将父进程的地址空间完全复制到子进程。vfork保证子进程会先运行。
exec函数只是用另一个新程序替换了当前进程的正文、数据、堆和栈段。

进程有三种正常终止法及两种异常终止法。不管哪种情况,最后都会执行内核中的同一段代码。该段代码为相应进程关闭所有打开描述符,释放它所使用的存储器等等。终止进程会通知其父进程它是如何终止的。

信号
信号是通知进程已发生某种条件的一种技术。
信号是软件中断。
信号提供了一种处理异步事件的方法。

进程处理信号有三种选择:
1. 忽略该信号。
2. 按系统默认方式处理。
3. 提供一个函数,信号发生时则调用该函数。

早期UNIX系统的一个特性是:如果在进程执行一个低速系统调用而阻塞期间捕捉到一个信号,则该系统调用被中断不再继续执行。该系统调用返回出错,其errno设置为EINTR。
好处:意味着已经发生某种事情,所以是个好机会应当唤醒阻塞的系统调用。

产生信号后,内核通常在进程表中设置某种形式的一个标志。当做了这个动作,我们就说向一个进程递送了一个信号。在信号产生到递送之间的时间间隔,称为信号未决(pending)。
进程可以阻塞某个信号。除非对被阻塞的信号的动作是忽略,否则该进程将此信号保持在未决状态,直到阻塞解除。进程调用sigpending函数将指定的信号设置为阻塞和未决。
每个进程都有一个信号屏蔽字,它规定了当前要阻塞递送的信号集。进程可以调用sigprocmask来检测和更改信号屏蔽字。
kill函数将信号发送给进程(组)。raise函数则允许进程向自身发送信号。
alarm函数设置闹钟时间,时间超过设置值时默认行为是终止进程。
pause函数使进程挂起直到捕捉到一个信号。

sigaction函数的功能是检查或修改(或两者)与指定信号相关联的处理动作。此函数取代UNIX早期版本中使用的signal函数。
用于信号处理程序中作非局部转移时应用sigsetjmp和siglongjmp函数。
sigsupsend函数恢复信号屏蔽字,然后使进程睡眠。

可再入函数
可再入函数是信号处理程序可以放心调用的函数。像malloc,如果malloc过程捕捉到信号,信号处理程序又malloc,这就会带来问题,所以它不是可再入函数。10.6表10-3列出了所有的可再入函数。若在信号处理程序中调用一个不可再入函数,则其结果是不可预见的。

进程间通信
IPC (InterProcess Communication)。作者建议:学会使用管道和FIFO,尽可能避免使用消息队列以及信号量,而应当考虑流管道和记录锁。
管道、FIFO、流管道、命名流管道、消息队列、信号量、共享存储这7种IPC通常限于同一台主机的各个进程间的IPC。套接字和流则支持不同主机上各个进程间IPC。
管道是UNIX IPC最老的形式,有两种限制:
1)它们是半双工的。
2)它们只能在具有共同祖先的进程之间使用。
流管道没有管道的第一种限制,FIFO和命名流管道没有第二种限制。

main函数是如何调用的?
内核用exec函数启动C程序。在调用main前先调用一个特殊的启动例程(可执行程序文件将此启动例程指定为程序的起始地址——这是编译、链接的时候设置的)。启动例程从内核取得命名行参数和环境变量值,然后为调用main函数做好准备。从main返回后,启动例程会立即调用exit函数。

进程终止
_exit函数立即进入内核,而exit函数则先执行一些清除处理,再进入内核。
atexit函数登记至多32个函数,这些函数将由exit自动调用,它们被称为exit handler。

设置-用户-ID和设置-组-ID
对各种不同的用户ID和组ID(实际、有效和保存的)的理解和编写安全的设置-用户-ID程序是至关重要的。运行设置-用户-ID程序的进程通常得到额外的权限,所以编写这种程序要特别谨慎。

以上内容转自互联网,现总结一下本书需要掌握的函数:
文件I/O
open()、close()、lseek()、read()、write()、dup()和dup()2、fcntl()。
文件和目录
stat()、fstat()、lstat()、access()。
标准I/O库
fopen()、fclose()、fread()、fwrite()、fget()、fseek()、ftell()、fcntl()。
进程控制
fork()、vfork()、exit()、wait()、waitpid()、system()。
信号
signal()、kill()、raise()、alarm()、pause()、sigprocmask()、sigpending()、sigsuspend()、sigaction()、abort()、sleep()。
线程
pthread_self()、pthread_create()、pthread_exit()、pthread_join()、pthread_detach()、互斥量、条件变量。
高级I/O
I/O多路转接:select()、poll()、epoll()。
进程间通信
消息队列、信号量semget()、sembuf()、共享内存shmget()、shmctl()、shmat()、shmdt()。
网络IPC:套接字
TCP/UDP:socket()、htons()、inet_pton()、bind()、connect()、listen()、accept()、send()、sendto()、recv()、recvfrom()。

UNIX环境高级编程学习总结相关推荐

  1. Unix环境高级编程学习笔记(七) 多线程

    线程概述 线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者.传统的Unix也支持线程的概念,但是在一个进程(process ...

  2. Unix环境高级编程学习笔记(一)

    第二章 文件I/O 1.文件描述符   对于内核而言,所有打开的文件都通过文件描述符引用,文件描述符是一个非负整数.   Unix shell使用文件描述符0表示标准输入,1表示标准输出,2表示标准出 ...

  3. Unix环境高级编程学习笔记(五)

    第七章 进程环境 1.main函数:int main(int argc, char *argv[]) 2.进程中止: 正常中止:(1)从main返回;(2)调用exit;(3)调用_exit或_Exi ...

  4. UNIX环境高级编程 学习笔记 第十六章 网络IPC:套接字

    socket的设计目标之一:同样的接口既可以用于计算机间通信,也可以用于计算机内通信.socket接口可采用许多不同的网络协议进行通信,本章讨论限制在因特网事实上的通信标准:TCP/IP协议栈. 套接 ...

  5. Unix环境高级编程学习笔记(二)

    第四章 文件和目录 本章将描述文件系统特征和文件性质 1.stat.fstat和lstat函数 原型:#include<sys/stat.h> int stat(const char* r ...

  6. 《Unix环境高级编程》学习笔记:从点到面

    以前在课堂上学习过<Unix初级教程(第四版)>,对于Unix有了一点了解.由于以后使用的需要,要对它进行比较深入的学习,为此需要阅读不少的书籍,这本<Unix环境高级编程>便 ...

  7. 《UNIX 环境高级编程》学习笔记—— 标准I/O库

    UNIX环境高级编程--标准I/O库 流和 FILE 对象 标准输入.标准输出和标准错误 缓冲 打开流 读和写流 每次一行 I/O 二进制 I/O 定位流 格式化 I/O 临时文件 内存流 流和 FI ...

  8. 5w字总结 Unix系统编程学习笔记(面试向)(Unix环境高级编程/Unix环境程序设计)

    文章目录 一.计算 C语言的数据表示与处理 计算 C语言的基本运算操作 内存表和符号表 类型转换 函数类型的分析 指令 复合指令 句法 函数 函数激活(Activation Record) 函数激活定 ...

  9. 《UNIX 环境高级编程》学习笔记——UNIX 基础知识

    UNIX环境高级编程--UNIX 基础知识 引言 UNIX 体系结构 登录 文件和目录 输入和输出 程序和进程 出错处理 用户标识 信号 时间值 系统调用和库函数 引言 所有操作系统都为它们所允许的程 ...

  10. Unix——学习《Unix环境高级编程》找不到“apue.h”方法

    在运行<UNIX环境高级编程>中的程序时会遇到apue.h包头找不到的情况,这是作者为了方便程序书写封闭了一些功能函数和错误处理等.在http://www.apuebook.com中可以下 ...

最新文章

  1. Enabling HierarchyViewer on Rooted Android Devices
  2. 计算星期几(信息学奥赛一本通-T1083)
  3. 单片机按键使用程序 (51单片机)
  4. cmd对应linux sleep命令,linux sleep命令参数及用法详解(linux休眠延迟执行命令)
  5. ParaView绘制gprMax正演模拟的波场快照方法(1)
  6. 简易售货机JAVA sql_自动售货机 - 笨拙的小Q的个人空间 - OSCHINA - 中文开源技术交流社区...
  7. Sonar问题及解决方案汇总
  8. [BZOJ 1025] [SCOI2009] 游戏 【DP】
  9. mysql5.7.17启动失败_解决Mysql5.7.17在windows下安装启动时提示不成功问题
  10. form 表单添加请求头_Golang GinWeb框架5-绑定多种请求类型的数据
  11. matlab视频教程矩阵,《机器学习》之矩阵和Matlab教程(适合初学)
  12. 知识图谱嵌入:TransE算法原理及代码详解
  13. 斐波那契数列——java实现
  14. 请问苹果x是如何建文件夹_教你12个技巧,最全苹果X使用教程。
  15. 74hc595数码管C语言,74HC595 数码管程序
  16. 检测X光图像中Covid-19
  17. Spark+Scala:数据分析统计
  18. Windows平台chrome webdriver的下载与安装
  19. Web是什么,Web简单介绍
  20. Dockerfile构建镜像并发布镜像

热门文章

  1. Ubuntu安装yum
  2. 计算机网络教程第五版|微课版 - 第一章 概述 - 习题
  3. 参考文献格式、论文尾注
  4. git send-email 使用126邮件发送patch
  5. 4816 江哥的dp题b
  6. unity漂移 unity3d教程 // WheelCollider
  7. Odoo实施指南 连载三:成功案例
  8. 几个国内的 apple 相关社区
  9. 【matplotlib】画图怎样将中文为宋体-英文为新罗马字体
  10. 泊松分布与指数分布的理解