linux-interface
November 11, 2018
The linux programming interface
基本概念
内核
- 通常的定义,1)完整的软件包, 这包括用来管理计算机资源的核心软件 以及附带的标准软件工具(shell,图形用户界面, 文件工具)2) 狭义的层面,是指管理和分配计算机资源的核心软件
- 职责: 1)进程调度, 2)内存管理, 3)文件系统, 4)创建和终止进程, 5)设备管理, 6)联网, 7)提供系统调用的编程接口
- 内核态、用户态: 区分态的原因: 1)只有cpu处于内核态的时候,才能执行某些命令, 例如 halt etc, 2)区分进程以及内核,能够让开发者 以面向进程的方式来编写 软件。 通过进程隔离 硬件计算机资源
用户和组
- 用户, 唯一的登录名和与之对应的整数型用户ID, 系统密码文件 /etc/passwd,为每个用户记录一行, 包含信息主要有: 组 ID, 主目录, 登录shell
- 组, 系统组文件 /etc/group, 包含信息主要有: 组名, 组 ID, 用户列表
- 超级用户, ID 为 0,可以不受系统权限检查之上。 可以访问系统的所有文件, 能发送信号给其他用户的进程
单根目录层级、目录、链接、文件
内核维护者一套单根目录结构, 放置系统的所有文件, /根目录 图
- 文件类型: 1) 普通文件, 2)设备, 3)管道, 4)套接字, 5)目录以及符号链接
- 路径和链接(hard link), 一个文件可以有多个链接,目录可以包含 文件 + 目录, 每个目录至少有两个链接, .和.. 指向目录自身的链接,已经指向上级目录的链接,根目录 “/”,的..指向自身
- 符号链接(soft link), 普通链接(hard link)的内容为 文件名+指针 的一条记录, 符号链接则是: 经过特殊标记的文件, 文件 + 目标文件字符串。多数情况下, 系统调用到了 路径名,如果是符号链接的情况下, 内核会自动 以符号链接 所指向的文件名来替换符号链接。递归的进行解析,为了防止循环解析, 内核对解析次数进行了限制。
- 文件名, 文件名应该避免以-字符串开头,避免 误认为命令选项开关
- 路径名: 绝对路径, 相对路径(定义了相对于进程当前工作目录的文件位置)当前工作目录(每个进程都有一个当前工作目录, 也是进程解释相对路径名的参照点, 进程的当前工作目录继承自 父进程, 相对登录shell来说 其初始当前工作目录为 密码文件 /et/passwd 中指定的,可以使用cd 改变)
- 文件的所有权:系统将用户分为3类, 文件的属主、文件属组成员、其他用户, 目录也可以设定所有权,但是意义有所不同,读写 允许列出目录内容, 写 允许对目录内容更改, 执行 允许对目录文件进行访问
- 文件IO模型, 同一套系统调用(open、read、write、close等)所执行的IO操作,可以应用于所有文件类型, 本质而言, 内核只提供一种文件类型, 字节流序列
- 文件描述符: 非负整数,来指代 打开的 文件。通常shell启动的进程会继承 3个已经打开的文件描述符, 0 为标准输入, 1 标准输出, 2 标准错误。在stdio函数库中, 分别与 stdin, stdout, stderr一一对应
- stdio 函数库: C 语言标准库的IO函数,例如fopen, fclose, printf 等,注意stdio 函数建立在 系统调用write, open close read之上
进程
进程是 正在执行的 程序实例, 执行程序时,内核会将程序代码再入到 虚拟内存, 为程序变量 分配空间,建立内核记账结构,用以记录进城有关的各种信息(PID, 状态)
- 进程的内存布局, 逻辑上: 文本, 数据,堆,栈
- 创建和执行程序, fork, 子进程会从父进程继承数据段、栈、堆 的副本,修改其内容,不会影响父进程。文本段则为父子进程共享。子进程要么继续执行父进程代码,要么执行execve 去加载一个全新的程序,execve会销毁现有的文本段、数据段、堆、栈,根据程序的代码重新创建并替换他们
- Pid && PPID: PPID 为父进程PID
- 进程终止和终止状态:两种方式杀死进程:1)exit() 系统调用请求退出, 2)向进程传递信号,将其杀死。无论那种方式进程退出,都会生成 『终止状态』一个非负数 小整数。可供父进程的wait 系统调用检测。exit()可以传递参数设定 终止状态, 信号杀死进程,则由信号类型设定进程的终止状态。, 0表示 功成身退, 非0 表示错误
- 进程标识:1)真实用户ID, 组ID,子进程继承父进程的 这些ID。登录shell,从/etc/passwd 中获取真实用户ID, 2)有效用户ID 组ID, 进程在访问受保护资源时候,会使用这两个ID来确定权限。3)补充组,用来表示进程所属的额外组。
- init 进程: 所有进程之父,相应的程序文件为/sbin/init, 并且以root权限运行,只有关闭系统才能杀死该进程。
- 守护进程:特殊用途的进程。特征, 1)守护进程通常在系统引导时启动, 直至系统关闭。2)在后台运行,无控制端 供其读取或者写入数据。(例如syslogd, httpd)
- 环境列表: 每个进程都有一份环境列表。fork创建的新进程会继承父进程的环境列表。这为父子进程 提供了一种通讯机制。进程调用fork, exec 可以通过环境列表来控制程序 行为。
- 资源限制:分为两类, soft limit, hard limit, 非特权进程调整 soft limit 只能在 0 - hard limit 之间, hard limit 只能调低。fork同样会继承父进程的limit
进程间通信及同步
- 信号: 表示事件的发生
- 管道: shell 中的 |, 以及FIFO
- 套接字: socket
- 文件锁
- 消息队列: 用于在进程间交换消息
- 信号量: 用于同步
- 共享内存: 允许两个及以上的进程共享同一块内存, 当进程改变了共享内存的内容时候, 其他进程会了解这一变化。
信号
软中断, 进程受到信号,意味着事件、错误异常的发生。信号类型有很多,采用不同的整数进行区分。以SIGxxxx的形式进行命名。
- 信号产生的情况有:
- 用户键入中断Ctrl-C
- 进程的子进程之一终止
- 进程设定的定时器 已到期
- etc …
- 信号处理:
- 信号从产生到送到期间,出去挂起状态。系统通常会在进程下次获得调度时,将挂起信号 送达。如果进程在运行中,则会立即将信号送达。
- 进程可以选择 接受、屏蔽信号。如果送达的信号处于屏蔽信号,此信号将一直挂起,直到 程序解除对信号的屏蔽
- 收到信号的动作有: 1)忽略信号、默认动作、设定自己的信号处理器, 2)被信号杀死, 3)挂起,之后使用专门的信号 唤醒
静态库和共享库
库: 将一组函数代码加以编译,并放置于文件中。 * 静态库: 早起UNIX 系统中唯一的目标库, 主程序代码对静态库中各个模块的不同函数代码加以引用,链接器解释这些引用,并从库中抽取所需要的目标模块的 副本。并复制到主程序的可执行文件中,这就是静态链接。缺点: 因为不同引用的主程序会存在引用的副本,导致浪费磁盘空间。 2 造成内存的空间的浪费,3 对共享库函数的修改,所有引用的主程序需要重新编译。 * 共享库: 将程序使用动态链接器编译,链接器就不会将库中引用的目标函数复制到可执行文件中,而是插入一条引用记录, 动态链接器 的程序 确保可执行文件在执行时候,所需的动态库能够找到。在运行时, 共享库的函数只保留一份,且可以工所有引用的程序使用,不仅节约了磁盘,内存空间。还能确保更改共享库之后,无需重新编译所有的引用了它的可执行文件。
线程:每个进程可以执行多个线程,他们共享同一虚拟内存、代码块、同一数据区和堆。只有属于各自的栈,用来保存本地变量和调用信息。
- 通信: 借助线程API提供的变量条件和互斥锁,来进行多个线程之间的同步
- 区别于进程: 多个线程可以方便的进行变量共享。
- 能够明显从多核处理器的并行处理中获益(为什么比多进程更好呢?)
/Proc 文件系统: Linux提供了/proc文件系统, 一种虚拟文件系统,以文件系统的目录和文件构成,提供了一个指向内核数据结构的接口。