1.1 引言
所有操作系统都为它们所运行的程序提供服务,典型的服务包括:
- 执行新程序
- 打开文件
- 读文件
- 分配存储区
- 获得当前时间
- …
1.2 UNIX体系结构
- 可将操作系统定义为一种软件,它控制计算机硬件资源,提供程序运行环境,通常将这种软件称为
内核
,因为它相对较小,而且位于环境的核心; - 内核的接口被称为
系统调用
; 公用函数库
构建在系统调用接口之上,应用程序既可使用公用函数库,也可以使用系统调用;shell
是一个特殊的应用程序,为运行其他应用程序提供了一个接口。
1.3 登录
1. 登录名
- 登录名保存在口令文件:
/etc/passwd
。
2. shell
- 登陆后,系统先显示一些系统信息,然后用户可以向
shell
程序键入命令; - UNIX系统常见shell:
1.4 文件和目录
1. 文件系统
- 文件系统是
目录
和文件
的一种层次结构,所有东西的起点是称为根
的目录,这个目录的名称是一个字符“/
”; - 目录是一个包含目录项的文件,即目录也是文件;
- 每个目录项都包含一个文件名和说明该文件属性的信息;
- 文件属性指文件类型、大小、所有者、权限、修改时间等。
2. 文件名
- 目录中的各个名字称为文件名;
- 斜线(/)和空字符不能出现在文件名中,斜线用来分隔构成路径名的各文件名,空字符用来终止一个路径名。
3. 路径名
路径名
:由斜线分隔的一个或多个文件名组成的序列(也可以斜线开头);绝对路径名
:以斜线开头的路径名称;相对路径名
:不以斜线开头的路径名称,指向相对于当前目录的文件;根
:文件系统的根是个特殊的绝对路径名,它不包含文件名。
4. 工作目录
- 每个进程都有一个工作目录,也称其为当前工作目录;
- 进程可以用
chdir
函数更改其工作目录。
5. 起始目录
- 登录时,工作目录设置为起始目录;
- 起始目录从口令文件中相应用户的登录项中取得。
1.5 输入和输出
1. 文件描述符
- 文件描述符是一个小的
非负整数
,内核用以标识一个特定进程正在访问的文件; - 内核打开、创建一个文件时,都返回一个文件描述符,读、写文件时,都可以使用这个文件描述符。
2. 标准输入、标准输出和标准错误
- 每当运行一个新程序时,所有shell都为其打开3个文件描述符,即:标准输入、标准输出、标准错误;
- 如果不做特殊处理,这3个描述符都链接向终端;
- 可将这3个文件描述符重定向到某个文件。
3. 不带缓冲的I/O
函数open、read、write、lseek以及close提供了不带缓冲
的I/O,这些函数都使用文件描述符。
4. 标准I/O
标准I/O函数为那些不带缓冲的I/O函数提供了一个带缓冲
的接口。
fgets
:读取一个完整的行;read
:读取指定字节数;getc
:读取一个字符;putc
:将字符写到标准输出。
1.6 程序和进程
1. 程序
程序
:是一个存储在磁盘上的可执行文件;- 内核使用
exec
函数将程序读入内存并执行程序。
2. 进程和进程ID
进程
:程序执行的实例,正在执行的程序;进程ID
:进程的唯一标识符,一个非负整数。
3. 进程控制
有3个用于进程控制的主要函数:
fork
exec
(7种变体,统称为exec函数)waitpid
4. 线程和线程ID
- 一个进程内的所有线程
共享
同一地址空间、文件描述符以及与进程相关的属性; - 线程
不共享
栈,每个线程有单独的栈、程序计数器PC; - 线程在访问共享数据时要采取
同步
措施以避免不一致性; 线程ID
:线程的唯一标识符,线程ID只在它所属的进程内起作用。
1.7 出错处理
当UNIX系统函数出错时,通常会返回一个负值,而且整型变量errno
通常被设置为具有特定信息的值,文件<errno.h>中定义了errno以及可以赋予它的各种常量,这些常量都以字符E开头。
errno的两条注意规则:
- 如果没有出错,其值不会被例程清除;
- 任何函数都不会将errno值设置为0,而且在<erroro.h>中定义的所有常量都不为0。
C标准中的两个用于打印出错信息的函数:
strerror
:将errnum(通常就是errno值)映射为一个出错消息字符串,并且返回此字符串的指针;
#include <string.h>
char *strerror(int errnum);
perror
:基于errno的当前值,在标准错误上产生一条出错信息,然后返回。
#include <stdio.h>
void perror(const char *msg);
1.8 用户标识
1. 用户ID
- 用户ID是一个数值,唯一标识各个不同的用户,在确定用户登录名时确定;
- 用户ID为0的用户为
根用户(root)
或超级用户。
2. 组ID
- 组ID也是一个数值,在指定用户登录名时分配;
- 多个登录项(用户)具有相同的组ID;
- 同组的各个成员之间共享资源。
3. 附属组ID
UNIX允许一个用户属于另外一些组,即一个用户可以属于多个组。
1.9 信号
信号用于通知进程发生了某种情况,进程处理信号的3种方式:
- 忽略信号;
- 按系统默认方式处理;
- 捕捉信号:提供一个函数,信号发生时调用该函数。
1.10 时间值
UNIX系统使用过的两种不同的时间值:
日历时间
:自协调世界时(Coordinated Universal Time,UTC)1970年1月1日00:00:00以来所经过的秒数
累计值,系统基本数据类型time_t
用于保存这种时间值;进程时间
:也称CPU时间,用以度量进程使用的中央处理器资源,以时钟滴答计算,每秒钟曾取50、60或100个时钟滴答,系统基本数据类型clock_t
用于保存这种时间值。
当度量一个进程的执行时间时,UNIX系统为一个进程维护了3个进程时间值:
时钟时间
:又称墙上时钟时间,它是进程运行的时间总量,其值与系统同时运行的进程数有关;用户CPU时间
:执行用户指令所用的时间量;系统CPU时间
:为该进程执行内核程序所经历的时间。
用户CPU时间和系统CPU时间之和常被称为CPU时间。
1.11 系统调用和库函数
- UNIX为每个系统调用在标准C库中设置一个具有同样名字的函数;
- 从实现者的角度来看,系统调用和库函数之间有根本的区别,但从用户角度来看,其区别并不重要;
- 应用程序既可以调用系统调用也可以调用库函数,很多库函数都会调用系统调用;
- 系统调用通常提供一种最小接口,而库函数通常提供比较复杂的功能。