apue 第十四章 高级IO

高级I/O

非阻塞I/O

低速系统调用:可能使得进程永远阻塞的一类系统调用

  • 读写管道、网络、终端
  • 在某些必要条件未发生之前,打开某些文件
  • 对已经上了锁的文件读写
  • 某些ioctl操作
  • 某些通信函数

读写磁盘文件虽然可能会短时间的阻塞,但也不是低速系统调用

非阻塞I/O可以通过两种方式获得

  • 在调用open的时候使用O_NONBLOCK标志
  • 可以使用fcntl函数进行设置

不同的设备的阻塞程度不一样

  • 我的wmware在书上实验中没产生阻塞返回
  • 而在secure CRT中基本上6000字节左右返回一下

书上的实验方式被称作轮询,占用CPU资源较大

  • 可以用多线程代替:但是同步又复杂而且还有同步的开销(上🔒)
  • 可以采用非阻塞的I/O多路转接

字节范围锁(record locking)

与读写锁的区别

  • 锁的粒度更细了
  • 读写锁是作用于线程之间的同步
  • 字节范围锁是针对于进程之间的同步
  • 字节范围锁是在获得文件描述符的一个属性:fcntl函数
  • 字节范围锁如果没法获得可以选择 获得失败或则阻塞等待两种状态。

一些实现细节

  • 如果进程以已经拥有一把相同位置的锁,如果继续申请相同的位置就会覆盖原来的锁
  • 锁的区域可以进行裂开或则合并
  • 利用F_GETLK不会报告自己进程拥有的锁,只会报告其它进程的锁
  • 系统检测出来一个死锁之后一般都是子进程返回错误

锁的隐含释放和继承

  • 一个进程释放的时候,其所建立的锁全部被释放
  • 任何时候关闭一个描述符,这进程通过这一个描述符所引用的文件上面的任何一把锁(与该文件、该进程相关的)都会关闭
  • 子进程不会继承父进程的锁

I/O多路转接

为啥需要多路转接?

  • 我们假想有一个这样的进程,有多个描述符,而且这些通过这些描述符进行数据交流。

  • 如果此时利用一个阻塞IO进行读写,而能就永远阻塞在一个描述符上面了

  • 可以利用多个进程分别负责这几个描述符,但是程序很变得更加的复杂

  • 可以来利用一个进程多个线程,但是增加同步性的,增加程序的复杂性

  • 也可利用非阻塞io以轮询进行每个描述符的读写,这样CPU受不了

  • 可以使用异步io,但是也有问题:1.并非所有的系统都支持2.我们发送的信号只有有一个,对多个描述符进行异步io,那接收到信号,我们去还是得每个描述符以非阻塞的方式去查询一下。

    • 异步io用于终端和网络,select用于所有的描述符

什么是多路转接技术

  • 先构造一张有关描述符的列表,然后去调用一个函数,直到有一个描述符中的一个已经准备好进行io了,函数返回我们想要知道的那个描述符

select 和pselect

  • select需要传入的参数和返回

    • 我们关心的描述符:三个fd_set结构(读、写和异常)

    • 我们愿意等待的时间:一个timeval结构

      • 时间设置为null:那么将永久等待(注意这儿等待是全部我们想知道的描述符等待,而不是单独的一个描述符)。直到捕捉到一个信号或者一个描述符准备好了返回
      • 时间设置为0:那么相当于轮询
      • 时间按设置为一个值:返回有三种可能,信号(-1),描述符准备好了(准备好的数量),时间过了 (0)
    • 返回哪些描述符是已经准备好了的

      • 返回-1(信号):不修改其中任何一个描述符集
      • 返回0(时间过来):所有的描述符集清零
      • 返回已经准备好的总描述符数:描述符集只留下准好好的描述符的对应位
  • pselect的不同

    • 时间结构更细了,用的timespec结构
    • pselect的超时值被设置为const,不能够被修改。而select是要被修改的
    • 增加了一个信号屏蔽功能,可以在等待期间屏蔽一些信号,在返回的之前恢复信号。

poll

  • 和select一样的功能,但是接口不太一样
  • 传入的是一个pollfd数组,里面有pollfd有fd,events(读,写还是出错),revents等东西,以代表一个fd的情况
  • 这儿与select不一样,当一个fd准备好了,不变events,而变的是revents。
  • select、poll这些在Linux系统当中都是不会自动重启的

readv和writev

也被称作散步读和聚集写

writev将从缓冲区散乱的数据,聚集写在一个文件中

readv将从读入的数据的数据,散乱的读在一个缓冲区的各个地方

有两种方法可以代替我们的散布读和聚集写:1.多次调用read和write 2.用write 的时候,先用一个大的缓冲区把散布的缓冲区聚集起来,一次调用write

但是我们写程序的时候最好用较少的系统调用来完成任务。(推介用readv和writev)

存储映射IO

使一个磁盘文件与存储空间中的一个缓冲区进行映射,但从缓冲区中取数据就是在文件中取数据

这个功能由mmap函数实现,其中函数中最重要就是两个参数:prot和flag参数

  • prot说明了映射区域被保护的要求:可读、可写、可执行等等。但是不能够超过打开文件open模式的访问权限
  • flag参数:控制在缓冲区的头地址、控制是否是存储操作是否改变文件的内容(shared)或则改变一个副本而已。

如果内存页已经被修改了,如何存储到我们的文件中去呢?

  • 利用我们的msync函数,相当于fsync函数(安全的,稳定的)
  • 或者等待着该页被调度就被写进我们的文件中去了

映射的关系什么被解除?

  • 进程终止,或者munmap函数之后映射被解除,munmap并不会将当前修改的页写进我们文件中
  • 关闭文件描述符并不会解除映射区
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值