apue读书笔记-第14章 高级IO

多路I/O转接



与select函数不同,poll不是为每个状态(可读性、可写性和异常状态)构造一个描述符集,而是构造一个pollfd结构数组,每个数组元素指定一个描述符编号以及其所关心的状态

readv和writev函数



作用:在一次函数调用中读、写多个非连续缓存区

总结:应当用尽量少的系统调用次数来完成任务。如果只写少量的数据,会发现自己复制数据然后使用一次write会比用writev更合算。但也可能发现,这样获得的性能提升并不值得,因为管理中间缓冲区会增加程序复杂度。

readn和writen函数



针对管道、FIFO以及某些设备,特别是终端、网络和STREAMS设备,一次读、写返回值可能小于要求值的情况,apue中定义了这两个函数,用于处理这类情况。

用户CPU时间、系统CPU时间、时钟时间



在阅读本章的过程,一直对三个概念比较模糊,即:用户CPU时间、系统CPU时间、时钟时间。参考了网上几篇文章后,总结如下:

  • 时钟时间:就是一个进程从开始运行到结束运行后,你的时钟走过了多少时间,这其中包含了进程在阻塞和等待状态的时间。
  • 用户CPU时间:就是用户的进程获得了CPU资源以后,在用户态执行的时间。
  • 系统CPU时间:用户进程获得了CPU资源以后,在内核态的执行时间。

习题



14.1

#include "apue.h"
#include <fcntl.h>
#include <errno.h>
void sigint(int signo)
{
}
int main(void)
{
    pid_t pid1, pid2, pid3;
    int fd;
    
    setbuf(stdout, NULL); // 将标准输出设置为无缓存
    signal_intr(SIGINT, sigint);
    if ((fd = open("lockfile", O_RDWR|O_CREAT, 0666) < 0))
    {
        err_sys("can‘t open/creat lockfile");
    }
    if ((pid1 = fork()) < 0)
    {
        err_sys("fork failed");
    }
    else if (0 == pid1)
    {
        if (lock_reg(fd, F_SETLK, F_RDLCK, 0, SEEK_SET, 0) < 0)
        {
            err_sys("child1: can‘t read-lock file");
        }
        printf("child1: obtained read-lock on file\n");
        pause(); // 使调用进程挂起直至捕获一个信号 
        printf("child1: exit after pause\n");
        exit(0);
    }
    else
    {
        sleep(2);
    }
    if ((pid2 = fork()) < 0)
    {
        err_sys("fork failed");
    }
    else if (0 == pid2)
    {
        if (lock_reg(fd, F_SETLK, F_RDLCK, 0, SEEK_SET, 0) < 0)
        {
            err_sys("child2: can‘t read-lock file");
        }
        printf("child2: obtained read-lock on file\n");
        pause();
        printf("child2: exit after pause\n");
        exit(0);
    }
    else
    {
        sleep(2);
    }
    if ((pid3 = fork()) < 0)
    {
        err_sys("fork failed");
    }
    else if (0 == pid3)
    {
        // 0和SEEK_SET决定了加锁区域的开始位置, 即从文件头部开始偏移量为0的地方开始加锁
        // 加锁失败立刻返回
        if (lock_reg(fd, F_SETLK, F_WRLCK, 0, SEEK_SET, 0) < 0) // 长度为0意味着到文件尾
        {
            printf("child3: can‘t set write-lock: %s\n", strerror(errno));
        }
        printf("child3 about to block in write-lock...\n");
        // F_SETLKW为F_SETLK的阻塞版本, 若加锁失败则进程进入休眠, 直至可以加锁或被信号中断唤醒
        if (lock_reg(fd, F_SETLKW, F_WRLCK, 0, SEEK_SET, 0) < 0)
        {
            err_sys("child3: can‘t write-lock file");
        }
        printf("child3 return and got write lock???\n");
        pause();
        printf("child3: exit after pause\n");
        exit(0);
    }
    else
    {
        sleep(2);
    }
    
    if (lock_reg(fd, F_SETLK, F_RDLCK, 0, SEEK_SET, 0) < 0)
    {
        printf("parent: can‘t set read-lock: %s\n", strerror(errno));
    }
    else
    {
        printf("parent: obtained additional read-lock while, write-lock is pending\n");
    }
    printf("killing child1...\n");
    kill(pid1, SIGINT);
    printf("killing child2...\n");
    kill(pid2, SIGINT);
    printf("killing child3...\n");
    kill(pid3, SIGINT);
    exit(0);
}

14.2

在Linux下fd_set的定义为一个包含长整形数组的结构,为什么不直接定义成数组,原因是结构体之间可以通过C语言的赋值运算符直接赋值。

FD_* 都是通过内嵌汇编实现的位操作

时间: 2024-09-28 20:00:30

apue读书笔记-第14章 高级IO的相关文章

C++ primer plus读书笔记——第14章 C++中的代码重用

第14章 C++中的代码重用 1. 使用公有继承时,类可以继承接口,可能还有实现(基类的纯虚函数提供接口,但不提供实现).获得接口是is-a关系的组成部分.而使用组合,类可以获得实现,但不能获得接口.不继承接口是has-a关系的组成部分. 2. C++还有另一种实现has-a关系的途径——私有继承.使用私有继承,基类的公有成员和保护成员都将称为派生类的私有成员.这意味着基类方法将不会称为派生类对象公有接口的一部分,但可以在派生类的成员函数中使用它们. 3. 包含将对象作为一个命名的成员对象添加到

APUE读书笔记-第三章 文件I/O

今天看得挺快的,一下子就把第二章看完了,不过第二章也确实看得不仔细,这一章其实在程序设计中还是非常重要的,因为这一章的内容决定了程序的可移植性. 好了,回到这一章的主题文件I/O. 3.2节主要对文件描述符的概念进行了简单的介绍.根据APUE:文件描述符是一个非负整数.当打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符.我也简单地翻了一下LKD和<深入理解linux内核>,其中对于文件描述符的讲解不是很多,所以对于文件描述符也谈不出来太深入理解,各大家还是分享一篇blog吧.

APUE读书笔记-第四章 文件和目录

到第四章了,不知什么时候才能把这本书看完,耽误的时间太多了. 第四章是在第三章的基础上,主要描述文件系统的其他性质和文件的性质. 4.2 stat.fstat.fstatat.lstat函数 首先来看看这四个函数的原型: #include <sys/stat.h> ///usr/include/x86_64-linux-gnu/sys/ int stat (const char *__restrict __file, struct stat *__restrict __buf) int fst

APUE读书笔记-第六章 系统数据文件和信息

昨天看完了,今天来看看第六章.感觉第六章的内容不是非常重要.简单看看吧 6.2 口令文件 口令文件其实就是/etc文件夹下的passwd文件,但处于安全性的考虑,我们无法直接读取它.就是通过直接限制权限的方式对其进行保护,passwd文件具体权限如下: -rw-r--r-- 1 root root 可以看到只有root用户具有读写权限,与root同组的用户与其他用户仅具有读权限. 不过为了解决以上问题,Linux中给出了一系列数据结构与函数帮助我们操纵口令文件,首先是关键数据结构,定义位于/in

APUE读书笔记-第五章 标准I/O库

今天草草的把第四章结了,后面的内容分析的也不是很详细,就连书中的例子都没有怎么实验,还是等以后有机会吧. 从5.3节开始研究起吧,这一节主要谈了一个进程预定义的3个流,分别是标准输入.标准输出和标准错误,通过stdin.stdout.stderr引用.这里要和进程中的文件描述符STDIN_FILENO.STDOUT_FILENO.STDERR_FILENO相区分. /* Standard streams. */ extern struct _IO_FILE *stdin; /* Standard

Java编程思想读书笔记--第14章类型信息

7.动态代理 代理是基本的设计模式之一,它是你为了提供额外的或不同的操作,而插入的用来代替“实际”对象的对象.这些操作通常涉及与“实际”对象的通信,因此代理通常充当着中间人的角色. 什么是代理模式? 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问. 代理模式有什么好处? 在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 代理模式一般涉及到的角色有: 抽象角色:声明真实对象和代理对象的共同接口,这样一来在任何可以使用目标对象

apue读书笔记 - 第11章 线程

实例11-1 为在Ubuntu12.04上的运行结果与书中描述的不一致呢? 从pid来看这两个线程属于同一个进程,且线程ID也是指针形式的,Google后得知,书上讲的是以前的LinuxThreads实现,现在linux使用NPTL线程. 参考:Linux 线程模型的比较:LinuxThreads 和 NPTL 习题11.4 在回答该问题之前,我觉得得先弄清楚"互斥量"与"条件变量"之间的关系.因为书上说这两者一般是配套使用的. 考虑如下情况: 子线程B和子线程C都

《HBase权威指南》读书笔记9:第九章 高级用法

行键设计 高表与宽表 高表:表中列少行多 宽表:表中列多行少 Hbase只能按行分片,因此高表更有优势. 把需要检索的条件尽量放到行键rowkey里面去 宽表适合需要行级原子性的需求 辅助索引 由客户端管理索引:缺点比优点更多 带索引的事务型Hbase: ITHbase  (个人认为要远离在原本就不成熟的HBase上的更不成熟的封装) 带索引的Hbase: IHbase (个人认为要远离在原本就不成熟的HBase上的更不成熟的封装) 协处理器: 用钩子维护索引 搜索集成 用HBase存储数据,用

《C++ Primer 4th》读书笔记 第8章-标准IO库

原创文章,转载请注明出处:http://www.cnblogs.com/DayByDay/p/3936457.html