当前位置: 首页 > news >正文

UNIX环境高级编程——1.UNIX基础知识

UNIX基础知识

UNIX体系结构
  • 严格意义上来说,可以将操作系统定义为一种软件,控制计算机硬件资源,提供程序运行环境。通常把这种软件成为内核。
  • 内核的接口被成为系统调用(system call)。公共函数库构建在系统调用接口之上,应用程序既可使用公共函数库,也可使用系统调用。shell是一个特殊的应用程序,为其他应用程序提供接口。
  • 从广义上来说,操作系统包含了内核和一些其他软件,这些软件使得计算机能够发货作用,并且具有自己的特性。这些软件包含了系统实用程序(system utility)、应用程序、shell以及公用函数库等。
    unix
文件与目录
  • UNIX文件系统是目录和文件的一种层次结构,所有东西的起点是称为根(root)的目录,这个目录的名称是一个字符“/”。
  • 创建新目录时会自动创建了两个文件名:.(称为点)和…(称为点点)。点指向当前目录,点点指向父目录。在最高层次的根目录中,点点与点相同。
输入和输出
  • 文件描述符(file descriptor)通常是一个小的非负整数,内核用以标识一个特定进程正在访问的文件。
  • 每当运行一个新程序时,所有的 shell 都为其打开 3 个文件描述符,即标准输入(standard input)、标准输出(standard output)以及标准错误(standard error)。如果不做特殊处理,例如就像简单的命令ls,则这3个描述符都链接向终端。
  • 函数open、read、write、lseek以及close提供了不带缓冲的I/O。这些函数都使用文件描述符。
  • 两个常量STDIN_FILENO和STDOUT_FILENO定义在<unistd.h>头文件中,它们指定了标准输入和标准输出的文件描述符。在POSIX标准中,它们的值分别是0和1,但是考虑到可读性,我们将使用这些名字来表示这些常量。
  • 标准I/O函数为那些不带缓冲的I/O函数提供了一个带缓冲的接口。使用标准I/O函数无需担心如何选取最佳的缓冲区大小,使用标准I/O函数还简化了对输入行的处理(常常发生在UNIX的应用程序中)。
程序和进程
  • 程序(program)是一个存储在磁盘上某个目录中的可执行文件。内核使用exec函数(7个exec函数之一),将程序读入内存,并执行程序。
  • 程序的执行实例被称为进程(process)。某些操作系统用任务(task)表示正在被执行的程序。
  • UNIX系统确保每个进程都有一个唯一的数字标识符,称为进程ID(process ID)。进程ID总是一个非负整数。
  • 有3个用于进程控制的主要函数:
    • fork:创建一个新进程,新进程是调用进程的一个副本。
    • exec(七种变体):执行命令或程序文件
    • waitpid:返回子进程的终止状态(status 变量)
  • 通常,一个进程只有一个控制线程(thread)(某一时刻执行的一组机器指令)。
  • 一个进程内的所有线程共享同一地址空间、文件描述符、栈以及与进程相关的属性。因为它们能访问同一存储区,所以各线程在访问共享数据时需要采取同步措施以避免不一致性。
  • 与进程相同,线程也用ID标识。但是,线程ID只在它所属的进程内起作用。一个进程中的线程ID在另一个进程中没有意义。
出错处理
  • 对于 errno 应当注意两条规则。第一条规则是:如果没有出错,其值不会被例程清除。因此,仅当函数的返回值指明出错时,才检验其值。第二条规则是:任何函数都不会将 errno 值设置为0,而且在<errno.h>中定义的所有常量都不为0。
用户标识
  • 用户 ID 为 0 的用户为根用户(root)或超级用户(superuser)
  • 现今的UNIX系统使用32位整型数表示用户ID和组ID
信号
  • 信号(signal)用于通知进程发生了某种情况。例如,若某一进程执行除法操作,其除数为0,则将名为SIGFPE(浮点异常)的信号发送给该进程。
  • 进程有以下3种处理信号的方式。
    • 忽略信号
    • 按系统默认方式处理
    • 提供一个函数,信号发生时调用该函数,这被称为捕捉该信号
  • 在一个进程中调用此函数就可向另一个进程发送一个信号。当然这样做也有些限制:当向一个进程发送信号时,我们必须是那个进程的所有者或者是超级用户。
时间
  • 日历时间:自协调世界时(Coordinated Universal Time, UTC)以来所经过的秒数累计值。系统基本数据类型time_t用于保存这种时间值。
  • 进程时间:CPU时间,用以度量进程使用的中央处理器资源。进程时间以时钟滴答计算。系统基本数据类型clock_t保存这种时间值。
    • 时钟时间:进程运行的时间总量,其值与系统中同时运行的进程数有关。
    • 用户CPU时间:执行用户指令所用的时间量。
    • 系统CPU时间:为该进程执行内核程序所经历的时间。
系统调用和库函数
  • UNIX所使用的技术是为每个系统调用在标准C库中设置一个具有同样名字的函数。用户进程用标准C调用序列来调用这些函数,然后,函数又用系统所要求的技术调用相应的内核服务。
  • 系统调用通常提供一种最小接口,而库函数通常提供比较复杂的功能。
习题
  • 1.1:在系统上验证,除根目录外,目录.和…是不同的。

    • 答:在根目录执行ls .和ls …输出不变
  • 1.2:分析图1-6程序的输出,说明进程ID为852和853的进程发生了什么情况?

    • 答:在大多数的Linux/Unix系统中,生成一个进程ID的方法是从0开始依次连续分配,所以在两次程序运行之间,系统创建了两个新的进程。
  • 在1.7节中,perror的参数是用ISO C的属性const定义的,而strerror的整型参数没有用此属性定义,为什么?

    #include <string.h>
    char *strerror(int errnum);
    
    #include <stdio.h>
    void perror(const char *msg);
    
    • 答:函数声明中,strerror传参是int类型,会发生值的拷贝,不会修改原来的值,而perror传参是const char*类型,传的是地址,如果不适用const修饰符,在函数内修改了值会导致外部变量的值也发生变化。
  • 若日历时间存放在带符号的32位整型数中,那么到哪一年它将溢出?可以用什么方法扩展溢出浮点数?采用的策略是否与现有的应用相兼容?

    • 答:带符号的32位整型数能表示的最大值是2147483647,约为68.09625973年,也就是说会在格林威治时间2038年01月19日溢出。采用double扩展溢出浮点数,不过问题是浮点数与现有的定点数应用无法兼容。
  • 若进程时间存放在带符号的32位整型数中,而且每秒为100时钟滴答,那么经过多少天后该时间值将会溢出?

    • 答:也就是计算时钟滴答什么时候溢出,2147483647 / 3600 / 24 / 100 = 248.55
参考资料
  • http://c.biancheng.net/view/314.html
随书练习源码地址
  • https://github.com/Johncdy/BookSource/tree/main/Advanced_Programming_in_the_UNIX_Environment

相关文章:

  • 哪个网站可以做公务员考试题/互动营销平台
  • 网站建设费与无形资产/网站seo是什么
  • 网站seo方案/免费b站推广网站破解版
  • 网站策划与维护/重庆网站关键词排名
  • 家居企业网站建设新闻/怎样搭建自己的网站
  • 商城网站seo/免费b2b推广网站大全
  • Unprojecting_text_with_ellipses过程分析
  • OpenCV基础入门
  • PMP备考大全:经典题库(敏捷管理第12期)
  • Android | Activity 启动流程分析
  • 认证鉴权对于 API 网关的重要性
  • web开发前基础知识补充
  • 【HDR】曝光融合(Exposure Fusion)
  • Vue混入(Vue.mixin)
  • 【BBuf的CUDA笔记】二,解析 OneFlow BatchNorm 相关算子实现
  • 【QT开发笔记-基础篇】| 第五章 绘图QPainter | 5.8 画刷设置
  • [力扣c++实现] 581. 最短无序连续子数组
  • 网络实验之RIPV2协议(二)