设为首页 加入收藏

TOP

UNIX环境高级编程 心得笔记(二)
2017-10-10 21:06:09 】 浏览:7578
Tags:UNIX 环境 高级 编程 心得 笔记
是一个非负数,且在当前时刻是唯一的。


有3个可以用于控制进程的系统调用:fork、exec和waitpid。其中exec是一系列函数的统称。


通常,一个进程只有一个线程。使用多线程能够充分利用多处理器系统的并行能力。一个进程内的所有线程共享当前进程的所有内存空间、文件描述法、栈以及进程相关的属性。由于所有进程共享进程的内存空间,因此在访问共享数据时需要采取同步措施以避免数据的不一致。


同进程类似,线程也有一个ID唯一标识每一个进程,但线程的ID只在进程内部有效,进程外部则无意义。线程也有特意用于控制线程的系统调用,后续学习。


当UNIX系统调用API函数出错时,通常会返回一个负值,这个返回值和进程返回给系统的返回值不相同,进程返回给系统的状态值范围是0 ~ 255。系统调用API函数通常会将该错误返回值赋给errno,errno变量看起来像是一个int类型的变量,但实际上并不是,早期的时候,它被简单的用int类型变量实现,但随着多线程出现之后,一个进程的errno变量是被多个线程共享的,当某一个线程因为出错而改变了errno变量之后,其他线程无法根据errno来判断自己当前的状态,造成了混淆,因此现在它通常被实现为一个函数调用,如下:



该定义在头文件 errno.h 中,首先声明了一个函数原型,该函数不接受参数,返回值是一个int * (int指针),errno定义为函数返回值(指针)的解引用。


C语言标准库函数提供了两个函数可以用于转换errno的值到具体的错误信息,如下:


strerror函数将errno变量的值转换为对应的具体错误信息,错误信息存储于字符串中,该字符串通过函数返回值指针指明。


perror函数将先打印msg消息,然后跟上一个冒号和一个空格,接着是errno值对应的可读错误信息,最后换行。


对于上面两个函数的使用示例如下:


上面的程序中,手动设置了errno变量为2,strerror函数将错误信息通过指针返回,代码使用标准输出打印其具体信息。perror接受一个信息参数,先打印传入的信息,然后是冒号和空格,随后是具体错误信息和换行。代码执行结果如下:



当出错的时候,错误分为两种:致命和非致命的。对于致命错误,无法恢复,只能打印错误信息、写日志,然后退出。而非致命的错误,一般是能恢复的,通常是等待一段时间后再试。


用户标识也是通过ID来进行区分的,该ID称为用户ID,它是一个数字。当一个用户创建时,会在/etc/passwd文件中生成唯一的用户ID,用户不能更改这个ID,除非是root用户才允许修改。


ID号码为0的用户是root用户,或者说是超级用户,该用户的用户名默认是root,也可以修改为其他的。如果一个进程拥有超级用户的特权,则大多数文件文件检查步骤都会被忽略。


用户除了用ID来进行区分,也用组来进行划分管理,相应的,其也有组ID,也是一个数字。与用户ID不同,一个用户只能有一个用户ID,多个用户名对应一个ID时,还是一个用户,系统只会根据ID来识别,而不会根据用户名来识别。而用户的组用户ID不唯一,一个用户可以拥有多个组ID,这表明该用户加入了多个小组。组的目的是为了让多个用户共享一个资源。组相关的配置文件是/etc/group。


用户ID和组ID使用数字来表示是历史遗留下来的,因为文件系统中的每个文件都要存储用户的ID和GID信息,使用数字可以只用4个字节即可存储。另外,如果使用字符串作为ID表示,则字符串之间的比较相对于数字更耗时。


可以通过 getuid( ) 和 getgid( )函数来获得相应的用户ID和组ID,如下:


信号是UNIX系统用于发送通知的一种机制,比如某个进程访问的内存地址超出了它的范围,则系统会发送一条通知至该进程,进程收到信号通知后,有3种应对处理方法:


1.忽略信号。收到之后什么也不做,当做未发生一样。


2.请系统处理。此方式告诉系统在收到信号时按系统的规定来处理。


3.提供一个处理函数。此方式在收到信号之后,用提供的函数来进行处理。


举个例子来说,假设我们现在有一个程序,它可以有三种方式来应对用户通过键盘Ctrl+C发出的中断信号。对于1.忽略信号,程序会忽略Ctrl+C,这将导致用户按Ctrl+C时没有任何反应,好似没有按Ctrl+C一样。对于2.请系统处理,系统会察觉到进程收到了一个信号,然后用默认的规则来处理,对于Ctrl+C发出中断信号,默认是终止程序,则我们的程序会被结束。对于3.提供一个处理函数来说,程序使用提供的函数处理,可以打印一些日志,等待几秒后退出程序,也可以做其他操作。


UNIX中谈及的时间可能有两种,一种是指当前客观世界的时间是多少,比如现在是几点几分,其表示方法通过自1970年1月1日以来经过了多少秒的形式,其类型为time_t。另一种是进程时间,也称为CPU时间,用来衡量进程执行耗费资源的计量,其类型为clock_t。


UNIX系统会为一个进程维护3个时间值:时钟时间、用户CPU、系统CPU。其中时钟时间指的是一个进程从运行开始到结束总共花去了多久的时间,它与当前系统中运行了多少进程和系统调度策略有关。用户CPU指的是进程用于执行用户指令花去的时间,系统CPU指的是为进程执行内核程序花去的时间。当一个进程执行了系统调用时,进程的CPU状态就会陷入内核,从而在管态下执行指令,这段时间就是系统CPU时间。用户CPU和系统CPU之和被称为CPU时间,也是程序真正执行耗费的时间。


我们可以用time命令来得知一个程序执行所花费的时间:



所有的UNIX系统都提供多种服务的入口点,由此程序可以向内核请求服务。各种UNIX都提供了良好定义、数量有限、直接进入内核的入口点。这些入口点被称为系统调用。


系统调用接口在man手册的第二部分中说明,是使用C语言定义的。


公用函数库接口在man手册的第三部分中说明,也是使用C语言定义的。它们不一定是内核的入口点,部分会间接使用一个或多个内核系统调用,而有些则完全不使用。


从实现角度看,系统调用和公用函数库有着本质区别,一个是伴随内核而产生的,是不可替换的。另一个是编译器厂商根据语言标准而实现的,可以更新和替换。但从用户角度看,它们没有太大区别,显著的区别是公用函数库更好用,功能更加强。


1.1 在系统上验证,除根目录外,目录 . 和 .. 是不同的。



首先使用pwd打印当前目录,然后进入 . 再打印目录,可以看到仍是当前目录,之后进入 .. 再打印目录,可以看到进入了根目录。在根目录下之后,无论进入 . 还是 .. 都是根目录。


1.2 分析图1-6程序的输出,说明进程ID为852和853的进程发生了什么情况?


当前有两个新执行的进程占用了852和853的PID。


1.3 在1.7中perror的参数是用ISO C的属性const定义的,而strerror的整形参数没有用此属性定义,为什么?


对于perror( )和strerror( )的函数声明如下:


从上面的函数原型可以看到,perror的参数类型是一个指针,通过指针能够解引用从而修改指针所指的对象,通过使用const修饰,可以阻止函数意外改变对象。而strerror的参数是一个普通int类型,而C语言只支持传值调用,因此形参只是实参的拷贝,改变形参这并不会造成什么问题。


1.4 若日历时间存放在带符号的32位整型数中,那么到

首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇使用HttpClient调用接口 下一篇关于Java的“找不到或无法加载主..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目