1.5 I/O
<unistd.h>的两个常量STDIN_FILENO, STDOUT_FILENO是POSIX标准的一部分, 他们指定了标准输入和标准输出的文件描述符,他们的典型值分别是0和1。该头文件包含了很多UNIX系统服务的函数原型。
stdin和stdout常量定义在<stdio.h>中,表示标准输入和标准输出文件。
1.6 程序和进程
1.程序
是存放在磁盘上,处于某个目录中的一个可执行文件。使用6个exec函数中的一个由内核将程序读入存储器,并使其执行。
2.进程
程序执行的实例process。某些操作系统用任务task表示被执行的程序。getpid()返回进程ID。
3.进程控制
fork(), exec(), waitpid()
4.线程和线程ID
通常一个进程只有一个控制线程,但是如果不同部分各使用一个控制线程,那么整个问题解决起来就容易很多。在一个进程内的所有线程共享同一地址空间,文件描述符,栈以及与进程相关的属性。因为他们能访问同意存储区,所以各线程在访问共享数据时需要采取同步措施以避免不一致性。
在一个进程中,我们用线程ID引用相应的线程。
在进程模型建立后很久,线程模型才被引入到unix系统中,这两个模型之间存在复杂的相互作用。
1.7 出错处理
unix函数出错时,常常返回一个负值,而整形变量errno通常被设置为含有附加信息的一个值。
文件<errno.h>中定义了符号errno以及可以赋予它的各种常量,这些常量都以字符E开头。
在支持线程的环境中,多个线程共享进程地址空间,每个线程都有属于它自己的局部errno以避免一个线程干扰另一个线程。
例如:linux支持多线程存取errno,将其定义为:
extern int *__errno_location(void);
$define errno (*__errno_location())
对于errno应当知道两条规则: 1,如果没有出错,则其值不会被一个例程清楚。2,任一函数不会将errno值设置为0.
c标准定义了两个函数,它们帮助打印出错信息
#include <string.h>
char *strerror(int errnum);
或
#include <stdio.h>
void perror(const char *msg)
1.8 用户标识
1.用户id
用户ID为0的用户为root,如果一个进程具有超级用户特权,则大多数文件权限检查都不再进行。某些操作系统功能只限于向root提供,
它对系统有自由的支配权。
2.组id
用于将入感用户分到不同的项目组或部门中。这种机制允许同组的各个成员之间共享资源(如,文件)。
使用的系统调用: getuid(), getgid()
3.附加组id
除了口令文件对一个登录名指定一个组id外,大多数unix系统还允许一个用户属于另外的组,POSIX要求系统至少支持8个附加组。
1.9 信号
是通知进程发生某种情况的一种技术。处理信号的三种选择:忽略该信号;按系统默认方式处理;提供一个函数。
终端键盘上有两种产生信号的方法: 中断键(ctrl+c);退出键(ctrl + /)
另一种产生信号的方法是调用名为kill的函数。
发送信号的限制: 当向一个进程发送信号时,我们必须是该进程的所有者或者是超级用户。
系统调用:signal();
1.10 时间值
unix系统一直使用两种不同的时间值:
1.日历时间
该值是自自1970年1月1日00:00:00以来国际标准时间(UTC)所经过的描述累计值。 系统基础数据类型time_t用于保存这种时间值。
2.进程时间
也成为CPU时间,用以度量进程使用的CPU资源。以时钟滴答计算,历史上曾经取每秒50,60或100个滴答。可使用sysconf函数取得每秒时钟的滴答数,以clock_t保存该值。
当度量一个进程的执行时间时,unix系统使用三个进程时间值:
.时钟时间: 进程运行的时间总量;
.用户CPU时间: 是执行用户指令所用的时间;
.系统CPU时间:是为该进程执行内核程序所用的时间。
要取得时钟时间,用户时间和系统时间是很容易的,只要调用time()
1.11 系统调用和库函数
unix所使用的技术是为每个系统调用在标准的c库中设置一个具有同样名字的函数。用户进程用标准c调用序列来调用这些函数,然后,函数又用系统所要求的技术调用相应的内核服务,然后执行某个产生软中断进入内核的机器指令。
从实现角度看,系统调用和库函数之间有重大区别;必要时我们可以替换库函数,而通常却不能替换系统调用。
以malloc为例,有多种办法实现存储器分配和搜集,如果我们不喜欢malloc,可以定义自己的存储器管理程序,它很可能使用sbrk系统调用,事实上,很多软件包,他们使用sbrk实现自己的存储器分配算法。sbrk,他按指定字节数增加或减少进程的地址空间。