《Unix环境高级编程》——Unix基础知识

引言

所有操作系统都为它们所运行的程序提供服务。典型的服务有:执行新程序、打开文件、读文件、分配存储区、获得当前时间等。

UNIX体系结构

操作系统是一种软件,它控制计算机资源,提供程序运行环境。我们通常将这种程序称为内核(kernel),因为它相对较小,而且位于系统核心。

内核的接口称为系统调用(system call)。公用函数库构建在系统调用接口之上,应用程序既可以使用公用函数库,也可使用系统调用。shell是一个特殊的应用程序,为运行其他应用程序提供了一个接口。

广义上说,操作系统包括了内核和其他软件,例如系统实用程序、应用程序、shell以及公用函数库。

登录

1. 登录名

用户在登录UNIX系统时,先输入用户名,再输入口令。系统在口令文件(通常是/etc/passwd)中查看登录名。口令文件中的登录项由7个以冒号分隔的字段组成,依次是登录名、加密口令、数字用户ID、数字组ID、注释字段、起始目录、shell程序。

jinhq:x:1000:1000:jinhq:/home/jinhq:/bin/bash

系统将加密口令移到另一个文件中。

2. shell

用户登录后,系统先显示一些系统信息,然后用户就可以向shell程序输入命令。

shell是一个命令行解释器,它读取用户输入,然后执行命令。shell 的用户输入通常来自终端(交互式shell),有时来自文件(shell脚本)。

系统从口令文件中相应用户的登录项的最后一个字段了解为该用户执行哪一个shell

Bourne-again shell是GNU shell,所有Linux系统都提供这种shell。它的设计遵循POSIX标准,同时保留了与Bourne shell的兼容性。

文件和目录

1. 文件系统

UNIX文件系统是目录和文件的一种层次结构,所有东西的起点是根目录(root),这个目录的名称是"/"。

目录是一个包含目录项的文件。每个目录项都包含一个文件名,同时还包含说明该文件属性的信息。文件属性是指文件类型、文件大小、文件所有者、文件权限以及文件的最后修改时间。

2. 文件名

目录中的各个名字称为文件名。只有斜线(/)和空字符这两个字符不能出现在文件名中。

为了可移植性推荐只用以下字符:字母(a~z, A-Z)、数字(0~9)、句点(.)、短横线(-)和下划线(_)。

创建新目录时会自动创建两个文件名:.(称为点) 和 ..(点点)。点指向当前目录,点点指向父目录。根目录中点和点点相同。

3. 路径名

由斜线分割的一个或多个文件名组成的序列构成路径名(pathname),以斜线开头的路径名称为绝对路径名,否则时相对路径名。相对路径指向相对于当前目录的文件。

4. 工作目录

 每个进程都有一个工作目录,有时称为当前工作目录。所有相对路径名都从工作目录开始解释。

5. 起始目录

登录时,工作目录设置为起始目录,该起始目录是从口令文件中用户的登录项中取得的。

输入和输出

1. 文件描述符

文件描述符通常是一个小的非负整数,内核用于标识一个特定进程正在访问的文件。当内核打开一个现有文件或创建一个新文件时,它都返回一个文件描述符。在读写文件时,可以使用这个文件描述符。

2. 标准输入、标准输出和标准错误

每当一个程序运行时,所有的shell都为其打开3个文件描述符,即标准输入、标准输出和标准错误。如果不做特殊处理,这3个描述符都链接向终端。shell提供一种方法,使描述符能重定向到某个文件。

如:ls > file.list

3. 不带缓冲的I/O

函数open、read、write、lseek和close提供了不带缓冲的I/O。

4. 标准I/O

标准I/O函数为那些不带缓冲的I/O函数提供了一个带缓冲的接口。使用标准I/O函数无需担心如何选取最佳缓冲区大小。

程序和进程

1. 程序

程序是一个存储在磁盘上某个目录中的可执行文件。内核使用exec函数将程序读入内存,并执行程序。

2. 进程和进程ID

程序的执行实例称为进程(process)。

UNIIX确保每个进程都有一个唯一的数字标识符,称为进程ID。进程ID总是一个非负整数。

3. 进程控制

有3个用于进程控制的主要函数:fork、exec和waitpid。

4. 线程和线程ID

通常,一个进程只有一个控制线程——某一时刻执行的一组机器指令。

对于有些问题,如果有多个控制线程分别作用于它的不同部分,解决起来就很容易。另外,多个控制线程也可以充分利用多处理器系统的并行能力。

一个进程内的控制线程共享同一地址空间、文件描述符、栈以及进程相关属性。因为他们能访问同一存储区,所以各线程在访问共享数据时需要采取同步措施以避免不一致性。

与进程相同,线程也用ID标识。但是,线程ID只在所有的进程内起作用。

出错处理

当UNIX系统函数出错时,通常返回一个负值,变量errno也会被设置为具有特定信息的值。

文件<errno.h>中定义了errno以及可以赋与它的各种变量。

errno应注意两条规则。第一条:如果没有出错,其值不会被例程清除。所以,只有函数返回值指明出错时,才检验其值。第二条:任何函数都不会将errno设置为0,而且在<errno.h>中定义的所有常量都不为0.

C标准定义了两个函数,用于打印出错信息。

char *strerror(int errnum);

strerror将errnum映射为一个出错消息字符串,并返回字符串指针。

void perror(const char *msg);

perror首先输出有msg指向的字符串,然后是一个冒号,一个空格,接着是对应errno的出错消息。

出错恢复

<errno.h>中定义的错误分两类:致命性和非致命性。

致命性错误无法执行恢复动作。最多就是在屏幕上打印一条出错消息或写日志文件,然后退出。

非致命性错误,有时可以妥善地处理。大多数致命性错误只是暂时的(如资源短缺),系统活动较少时,这种出错可能不会发生。

与资源相关的非致命性错误有:EAGAIN、ENFILE、ENOBUFS、ENOLCK、ENOSPC、EWOULDBLOCK等。

对于资源相关的非致命性错误典型的恢复操作时延迟一段时间,然后重试。

用户标识

1. 用户ID

口令文件中的用户ID是一个数值,向系统标识各个不同的用户。用户不能更改用户ID。通常每个用户有一个唯一的用户ID。

用户ID为0的用户为根用户(root)或超级用户。如果一个进程有超级用户权限,大多数文件权限检查都不再进行。

某些操作系统功能只向超级用户提供。

2. 组ID

口令文件的登录项中也包括用户的组ID,它是一个数值。

组被用于将若干用户集合到项目或部门中去,允许同组的各个成员共享资源。

组文件将组名映射为数值的组ID,组文件是/etc/group.

3. 附属组ID

除了在口令文件中对一个登录名指定一个组ID外,多数UNIX系统还允许一个用户属于另外一些组。

信号

信号(signal)用于通知进程发生了某种情况。例如,某个进程执行除零操作,则将名为SIGFPE的信号发送给该进程。

进程有3种处理信号的方式:

1)忽略信号。不推荐

2)按系统默认方式处理。对于除0,系统默认终止进程。

3)提供一个函数,信号发生时调用该函数,这称为捕捉该信号。

时间值

UNIX系统使用两种不同的时间值:

1)日历时间。

该值是自协调世界时(UTC)1970年1月1日 00:00:00 这个特定的时间以来经过的秒数累计值。系统用time_t 保存这种值。

2)进程时间。

也被称为CPU时间,用于度量进程使用的中央处理器资源。进程时间以时钟滴答计算。

当度量一个进程的执行时间时,UNIX系统为一个进程维护了3个进程时间。

  • 时钟时间
  • 用户CPU时间
  • 系统CPU时间

时钟时间又称为墙上时间,它时进程运行的时间总量。

用户CPU时间是执行用户指令所用的时间量。系统CPU时间是为该进程执行内核程序所经历的时间。

用户CPU时间和系统CPU时间称为CPU时间。

系统调用和库函数

操作系统提供服务的入口点,由此程序项内核请求服务,这些入口点称为系统调用。

从实现者角度,系统调用和库函数有根本的区别,从用户角度看并不重要。如果需要,库函数可以被替换,系统调用是不能被替换的。

应用程序既可以调用系统调用也可以调用库函数。很多库函数则会调用系统调用。

系统调用通常提供一种最小接口,而库函数通常提供比较复杂的功能。

小结

本章快速浏览了UNIX系统,说明了以后会用到的基本术语。

发布了23 篇原创文章 · 获赞 0 · 访问量 978

猜你喜欢

转载自blog.csdn.net/u014635079/article/details/104264989