UNIX 环境高级编程Chapter 1.2

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>
int
main(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);  /*信号捕捉函数*/
 
int
main(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新增*/
void
sig_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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值