UNIX 环境高级编程Chapter 1.2

来源:互联网 发布:天干地支年月计算法 编辑:程序博客网 时间:2024/05/22 06:13

1-7出错处理

第一条规则是:如果没有出错,则其值不会被一个例程清除。
因此,仅当函数的返回值指明出错时,才检验其值。第二条是:任一函数都不会将 e r r n o值设置为0,在< e r r n o . h >中定义的所有常数都不为 0。

C标准定义了两个函数,它们帮助打印出错信息。
#include <string.h>
c h a r * s t r e r r o r ( i n t  errnum) ;
返回:指向消息字符串的指针
此函数将errnum(它通常就是 e r r n o值) 映射为一个出错信息字符串,并且返回此字符串的指针。

p e r r o r函数在标准出错上产生一条出错消息 (基于e r r n o的当前值),然后返回。
#include <stdio.h>
v o i d

p e r r o r (c o n s t c h a r    *m s g) ;
它首先输出由m s g指向的字符串,然后是一个冒号,一个空格,然后是对应于 e r r n o值的出
错信息,然后是一个新行符。

#include "apue.h"#include <errno.h>intmain(int argc, char *argv[]){fprintf(stderr, "EACCES: %s\n",strerror(EACCES));errno = ENOENT;perror(argv[0]);exit(0);}

结果:

$ ./a.out
EACCES: Permission denied
./a.out: No such file or directory

注意,我们将程序名 ( a rg v〔0〕,其值是 a.out) 作为参数传递给 p e r r o r。这是一个标准的
U N I X惯例。使用这种方法,如程序作为管道线的一部分执行,如:
prog1 < inputfile | prog2 | prog3 > outputfile

则我们就能分清三个程序中的哪一个产生了一条特定的出错消息。

出错恢复:致命性和非致命性

1.8用户标识

1.用户ID

口令文件登录项中的用户 I D(user ID)是个数值,它向系统标识各个不同的用户。

用户I D为0的用户为根 ( r o o t )或超级用户 ( s u p e r u s e r )。

调用g e t u i d和g e t g i d以返回用户I D和组I D。

2.组ID

对于用户而言,使用名字比使用数值方便,

所以口令文件包含了登录名和用户 I D之间的映射关系,

而组文件则包含了组名和组 I D之间的映射关系

3.附加组ID

 

1.9信号

有两种键盘方式,分别称为中断键 (interrupt key,通常是 D e l e t e键或C t r l - C )和退出键 (quit key,通常是 C t r l - \ ),它们被用于中断当前运行进程。

另一种产生信号的方法是调用名为 k i l l的函数。在一个进程中调用此函数就可向另一个进程发送一个信号。当然这样做也有些限制:当向一个进程发送信号时,我们必需是该进程的所有者。

#include "apue.h"#include <sys/wait.h>/*整体就是比1-5.c更加严谨---2017-5-1-15.25xc*/static void sig_int(int);  /*信号捕捉函数*/ intmain(void){char buf[MAXLINE];pid_t pid;int status;/*相比1-5.c新增,signal函数指定当产生SIGINT信号时要调用的函数名sig_int*/if(signal(SIGINT,sig_int)==SIG_ERR) err_sys("signal error"); /* from apue.h */printf("%% "); /* print prompt (printfrequires %% to print %) */ /*fgets返回的每一行都以换行符终止,后随一个null字节*/while (fgets(buf, MAXLINE, stdin) != NULL){/*strlen计算字符串长度,再用null(0)替换换行符*/if (buf[strlen(buf) - 1] == '\n')buf[strlen(buf) - 1] = 0; /* replace newline withnull *//*fork创建一个新进程*/if ((pid = fork()) < 0) {err_sys("fork error");} else if (pid == 0) {/* child */execlp(buf, buf, (char *)0);//fork配合execlp产生新进程err_ret("couldn’t execute: %s", buf);exit(127);}/* parent */if ((pid = waitpid(pid, &status, 0)) < 0)//父亲等儿子结束err_sys("waitpid error");printf("%% ");}exit(0);}/*相比1-5.c新增*/voidsig_int(int signo){ printf("interrupt\n%%");}


 

1.10 UNIX时间值

(1) 日历时间。该值是自1 97 0年1月1日0 0 : 0 0 : 0 0以来国际标准时间(U T C)所经过的秒数累计值(早期的手册称 U T C为格林尼治标准时间)。这些时间值可用于记录文件最近一次的修改时间等。
(2) 进程时间。这也被称为 C P U时间,用以度量进程使用的中央处理机资源。进程时间以时钟滴答计算,多年来,每秒钟取为 5 0、6 0或1 0 0个滴答。系统基本数据类型 c l o c k _ t保存这种时间值。

• 时钟时间。
• 用户C P U时间。
• 系统C P U时间。
时钟时间又称为墙上时钟时间( wall clock time)。它是进程运行的时间总量,其值与系统中同时运行的进程数有关。在我们报告时钟时间时,都是在系统中没有其他活动时进行度量的。
用户C P U时间是执行用户指令所用的时间量。系统 C P U时间是为该进程执行内核所经历的时间。例如,只要一个进程执行一个系统服务,例如 r e a d或w r i t e,则在内核内执行该服务所花费的时间就计入该进程的系统 C P U时间。用户 C P U时间和系统 C P U 时间的和常被称为C P U时间。

1 . 11 系统调用和库函数

从执行者的角度来看,系统调用和库函数之间有重大区别,但从用户角度来看,其区别并不非常应用代码重要。在本书中系统调用和库函数都以 C函数的形式出现,两者都对应用程序提供服务,但是,我们应当理解,如果希望的话,我们可以替换库函数,用户进程但是通常却不能替换系统调用。

从中可见,两者职责不同,相互分开,内核中的系统调用分配另外一块空间给进程,而库函数m a l l o c则管理这一空间。

系统调用和库函数之间的另一个差别是:系统调用通常提供一种最小界面,而库函数通常提供比较复杂的功能。

 

 

 

0 0