第一章: UNIX基础知识:
UNIX的体系结构:
最外层: 应用程序
次外层: 外壳(shell)-库函数(Lib)
shell是一个命令行解释器
库函数是封装好了的系统调用集合
内层: 系统调用(SysCall)
内核(Kernel)
注:
应用程序如何使用系统调用可以自主选择, 有三种方式
直接调用
调用库函数
通过操作系统的外壳程序
用户的登录:
口令文件
内容: (用户名,加密口令,UID,``GID`,注释,家目录,使用的shell程序路径)
shell
分类
文件和目录
文件系统
起点是根 (root)/
是树状的
文件名
命名规则:
不可以出现/和null
最大长度255
创建新目录会自动产生:
.表示当前目录
..表示上一级目录
路径名字:
用斜线分割各级目录
分类:
相对路径
绝对路径
工作目录
起始目录
输入和输出
文件描述符:
是个非负整数
用于描述文件的访问状态(在被谁访问)
stdio和stderr描述符:
默认指向终端
无需缓冲的I/O
stdio
程序和进程
程序
使用exec()读入内存
进程和PID
PID是系统识别进程的标识符
是个非负整数
进程控制
函数fork(), exec(), waitpid()
线程和TID
线程
依赖于进程的存在
各个线程共享数据,可互相通信
出错处理
出错返回负数
出错编号用来判断错误类型,有的程序额外定义了错误号
用户标识
每个用户存在唯一标识符:UID
超级用户UID为0
每个用户组存在唯一标识符:GID
信号
是系统发送给进程的消息
处理方法:
忽略
系统默认的终止
捕捉该信号, 转入事先设置好的相应的处理程序
产生:
Del和Ctrl+C和Ctrl+\
调用kill()
使用条件:是所有者/root
时间值
分类:
日历时间:
自1970-1-1以来的UTC时间
用于记录文件的修改时间
进程时间:
单位:tick
用于计量程序运行的
度量方式:
时钟时间
用户CPU时间
系统CPU时间
系统调用和库函数
是os提供服务的入口
第三章: 文件I/O
文件描述符:
作用:
高效管理已被打开的文件所创建的索引,用来区别不同的被打开的文件
内核通过文件描述符访问文件
文件描述符、文件、进程间的关系:
每个文件描述符会与一个打开的文件相对应;
不同的文件描述符也可能指向同一个文件;
文件描述符是文件的非单调函数
相同的文件可以被不同的进程打开,也可以在同一个进程被多次打开;
open函数
功能: 打开文件
参数:
文件名
函数选项(是个预先定义好的常数)
返回值: 文件描述符
出错会返回 -1
文件/路径名截短:
超出最大文件名长度的现象
处理方式:
由常量_POSIX_NO_TRUNC决定
自动截断
返回出错状态
creat函数
功能: 创建新文件
参数:
路径名字
文件访问权限
返回值: 文件描述符
注意事项:
该函数以只写WRITE_ONLY权限创建文件
close函数
功能:
关闭文件
给上了锁的文件解锁
调用时机:
进程终止时
lseek函数
偏移量:
含义:当前读取/写入的位置距离文件头的字节数
偏移量记录在内核之中
可以大于文件长度,下次读写时会自动加长,加长的都看作是0
分类:
32bit偏移量
64bit偏移量
功能:
为已经打开的文件设置/修改偏移量
默认值:
调用open()时,如果没附加O_APPEND选项则默认是0
参数:
偏移量offset:
坐标原点whence:
SEEK_SET: 从文件头部开始增加offset个字节
SEEK_CUR: 从当前位置…
SEEK_END: 从末尾开始…
read函数
功能:
从已经打开的文件读取数据
返回值:
成功则返回该字节对应的数
结尾(EOF)则0
参数:
文件路径名
几个字节
特殊情况:
有时会少于要求读入的字节数: 例如中断,末尾,网络设备缓冲等等
write函数
==向打开的文件==写文件
小结: 关于文件操作的函数
函数名 | 功能 | 参数 | 返回值 |
open() | 打开文件 | 文件名; 函数选项 | 文件描述符 |
creat() | 创建新文件 | 路径名字; 文件访问权限 | 文件描述符 |
close() | 关闭文件 给上了锁的文件解锁 | 文件描述符 | |
lseek() | 为已经打开的文件设置/修改偏移量 | 偏移量offset; 坐标原点whence | 新的文件偏移量 |
read() | ==从已经打开的==文件读取数据 | 文件描述符;几个字节 | 成功则返回该字节对应的数;结尾(EOF)则0 |
write() | ==向打开的文件==写文件 | 文件描述符 | 本次调用写入了的字节数 |
I/O的效率
BUFFSIZE 缓冲大小:
缓冲区越大,则CPU工作效率越高
适当增加缓冲区大小,缓冲区太大始终时间反而延长
文件共享
含义:
在不同进程之间共享打开的文件
实现方式(数据结构):
第一级: 每个PCB(进程控制块)内部有一个文件描述符表, 用来记录打开的文件
第二级: 系统内核将为==每一个进程==所有打开的文件编成一张表, 包含:(优点: 偏移量相互独立)
文件状态 | 偏移量 | 指针(指向v节点表头) |
第三级: v节点表(每个文件唯一, 这种唯一性有缺点)
v节点(表头): 指向对此文件进行操作的函数的指针
i节点(索引节点):用来指向文件本体
文件的所有者 | 长度 | 位置 |
总结: 文件的共享依赖于互不干扰的读写和访问,系统内核为每个进程分配的文件表(第二级)是关键
原子操作(原语)
含义:
由于各个进程需要用一张v节点表(第三级), 当读写文件进度不同时会引发冲突
(我刚写入的就被他当作空白而写入了他自己的东西)
dup2函数
功能: 复制一个已经打开的文件
参数
dup()函数: 文件描述符
dup2(): + 新文件描述符
返回值:
当前可用描述符的最小值
sync类函数
来源:
延迟写入
含义: 将读取的文件先放到缓存里,当缓存队列满时再输出到磁盘之中
优点: 减少磁盘I/O次数
缺点:
降低文件的更新速度
当系统故障时,未及时更新的内容会丢失
sync()
功能:
将所有修改过的块缓冲区排入“写队列”
排队之后直接返回
冲洗缓冲队列(块缓冲区)到磁盘之中
无返回值
fsync()
功能:
类似于sync(),
只对指定的文件的块缓冲区有作用
等写入磁盘之后才会返回
参数:
文件描述符
返回值:
success ? return 0:return -1;
fdatasync()
和fsync()一样,只不过会在更新文件(写入磁盘时候)同时改变文件的属性(比如时间)
解决方案:
update进程会周期性地将缓存队列中的内容调用sync(), 使得同步
fcntl函数
功能: 改变已打开文件的性质
可改变的性质
读取描述符
参数:
文件描述符
命令参数
返回值
成功: 依赖于命令参数所规定的常数
失败: -1
ioct函数
功能:
杂项I/O操作, 例如终端, 套接字等
参数:
文件标识符
请求
返回值:
成功? return 0:return -1
总结: 文件I/O函数
函数名 | 功能 | 参数 | 返回值 |
open() | 打开文件 | 文件名; 函数选项 | 文件描述符 |
creat() | 创建新文件 | 路径名字; 文件访问权限 | 文件描述符 |
close() | 关闭文件 给上了锁的文件解锁 | 文件描述符 | |
lseek() | 为已经打开的文件设置/修改偏移量 | 偏移量offset; 坐标原点whence | 新的文件偏移量 |
read() | ==从已经打开的==文件读取数据 | 文件描述符;几个字节 | 成功则返回该字节对应的数;结尾(EOF)则0 |
write() | ==向打开的文件==写文件 | 文件描述符 | 本次调用写入了的字节数 |
dup2() | 复制一个已经打开的文件 | 文件描述符(+新文件描述符) | 当前可用描述符的最小值 |
sync() | 将所有修改过的块缓冲区排入“写队列” ;排队之后直接返回 | 文件描述符 | {-1,0} |
fcntl() | 改变已打开文件的性质 | 文件描述符 命令参数 | {-1,0} |
ioct() | 杂项I/O操作, 例如终端, 套接字等 | 文件标识符 请求 | {-1,0} |