Linux 系统编程

时间:2023-12-30 10:34:38
  1. 简介和主要概念
  • Linux 系统编程最突出的特点是要求系统程序员对它们工作的的系统的硬件和操作系统有深入和全面的了解,当然它们还有库和系统调用上的区别。
  • 系统编程分为:驱动编程、用户空间编程和网络编程。
  • 系统编程有三大基石:系统调用、C库和C编译器。
  • 文件I/O
    • 文件I/O是Unix系统的核心,第三章会介绍基于C标准库的标准I/O,第四章继续讨论了更高级和专门化的I/O, 第七章以文件盒目录操作为主题结束了整个文件I/O部分的讨论。
    • 文件I/O包括 open, creat, read, write, close fsync(同步I/O), fdatasync(同步I/O),sync(同步I/O), lseek, truncate 函数。
    • Linux 提供了三种 I/O  多路复用的方法,select , poll , epoll。这三种方式有各自的优缺点,具体参考:
  • 缓冲输入输出
    • 要理解缓冲,首先要理解块,作为文件系统的抽象,它是 I/O 中最基本的概念,所有的磁盘操作都是基于块进行的。因此当请求以块大小整数倍对齐地址时,  I/O 效率是最理想的。
    • 标准 I/O 例程并不直接操作文件描述符,取而代之的是文件指针(file pointer)。在C标准库里,文件指针映射到文件描述符。
    • 在标准 I/O 里,一个打开的文件叫做“流”(stream)。
    • 标准 I/O 包括 fopen, fdopen, fclose, fclose, fgetc, ungetc, fgets, fread, fputc, fputs, fwrites, fseek, ftell, ferror, fileno, setvbuf 等等。
    • 标准 I/O 最大的缺点是双副本对性能造成的影响。当读取数据时,标准 I/O 对内核执行read()系统调用,从内核复制数据到标准 I/O 缓冲区。然后当通过标准 I/O 执行一个读请求时,数据又会从标准 I/O 的缓冲区复制到指定的缓冲区。
    • read/write和fread/fwrite区别
      • fread是带缓冲的,read不带缓冲.
      • fopen是标准c里定义的,open是POSIX中定义的.
      • fread可以读一个结构.read在linux/unix中读二进制与普通文件没有区别.
      • fopen不能指定要创建文件的权限.open可以指定权限.
      • fopen返回指针,open返回文件描述符(整数).
      • linux/unix中任何设备都是文件,都可以用open,read.
      • 如果文件的大小是8k。你如果用read/write,且只分配了2k的缓存,则要将此文件读出需要做4次系统调用来实际从磁盘上读出。如果你用fread/fwrite,则系统自动分配缓存,则读出此文件只要一次系统调用从磁盘上读出。也就是用read/write要读4次磁盘,而用fread/fwrite则只要读1次磁盘。效率比read/write要高4倍。如果程序对内存有限制,则用read/write比较好。都用fread 和fwrite,它自动分配缓存,速度会很快,比自己来做要简单。如果要处理一些特殊的描述符,用read 和write,如套接口,管道之类的系统调用write的效率取决于你buf的大小和你要写入的总数量,如果buf太小,你进入内核空间的次数大增,效率就低下。而fwrite会替你做缓存,减少了实际出现的系统调用,所以效率比较高。
      • 如果只调用一次(可能吗?),这俩差不多,严格来说write要快一点点(因为实际上fwrite最后还是用了write做真正的写入文件系统工作),但是这其中的差别无所谓。
  • 高级文件I/O
  • 进程管理
    • 进程是操作系统的基础,是程序的一次执行。是程序及其数据在处理机上顺序执行时所发生的活动。
    • 有两种方式创建新的进程:
      • fork 调用会导致创建一个子进程
      • exec调用则会用新的程序代替当前进程的上下文
    • 终止进程有以下几种方式:
      • exit
      • SIGTERM 和 SIGKILL
    • 子进程退出后,转变为僵尸进程,父进程调用 wait 和 waitpid 使得子进程完全退出
    • 许多Unix系统在他们的C函数库中提供了 daemon() 函数来完成 守护进程的创建工作。
  • 高级进程管理
    1. 7.  文件与目录管理
    2. 8.  内存管理
      • 内存管理包括: 存储器分配(allocation),内存操控(manipulation)和最后的内存释放(release)
      • 进程地址空间
        • 内存的基本单位是页,32位系统是4K,64位系统是8K
        • 每个进程所包含的存储器区域为:
          • 代码段(文本段)
          • 栈空间
          • 堆空间(数据段)
          • BBS段 --包含了没有被初始化的全局变量
      • 动态内存分配
        • malloc , calloc , realloc
      • 动态内存释放
        • free
      • 内存对齐
        • 一个结构的对齐要求和它的成员中最大的那个类型是一样的
        • 结构体也需要内存对齐
        • union的对齐和它所包含的最大的类型一致
        • 一个数组的对齐和数组中的元素类型一致
      • 匿名存储映射
        • 优点:
          • 无需关心碎片
          • 大小可调整
          • 每个分配存在于独立的内存映射,没有必要再求管理一个全局的堆
        • 缺点:
          • 存储器映射都是页面大小的倍数,容易浪费空间
          • 创建一个新的内存映射比从对中返回内存的负载要大
        • malloc()使用数据段满足小的分配,匿名存储映射用来满足较大的分配
      • 高级存储器分配
        • mallopt() 设置存储器管理相关的参数
        • malloc_usable_size()和 malloc_trim() 进行调优
        • 使用 MALLOC_CHECK 环境变量来开启存储系统额外的调试
          • MALLOC_CHECK_=1 ./rudder
      • 使用  mallinfo() 来获得关于动态存储分配的统计数据
      • Linux 系统编程

    9.  信号

      • 信号是提供处理异步事件机制的软件中断。
      • 内核处理信号的三种方式:
        • 忽略信号    SIGKILL 和 SIGSTOP 不可以被忽略
        • 捕获并处理信号
        • 执行默认操作,通常是终止程序
      • 映射信号编号为字符串
        • extern const char * const sys_siglist[];
        • printf("caught %s\n", sys_siglist[signo]);
      • 发送信号
        • kill()
      • 高级信号管理
        • sigaction()