从C语言系统调用函数read和write到Java阻塞IO

一 背景

作为一名Java代码搬运工,我们经常通过java.io包对进行操作IO。由于JVM跨平台的优点,能够帮开发者屏蔽底层细节,使我们不需要直接与操作系统打交道,更加专注业务开发。缺点也很明显,开发者对底层往往一脸懵逼。最近楼主重读了操作系统一书,对底层原理打破沙锅问到底。

二 用户程序读写原理

在Linux操作系统中,内存划分为用户空间内核空间,在4G内存的32位X86系统中,两者的内存占比是3:1。JVM想读取磁盘中的文件时候,可以直接读取?答案是否定的。硬件设备通常不能与用户空间交互,JVM属于用户进程,驻守在用户空间,所以JVM没法直接读取磁盘中的数据。正确的读流程是:1)用户进程底层使用C语言的read方法进行系统调用; 2)内核向磁盘控制器发送命令,要求其从磁盘读取数据; 3)磁盘控制器通过直接内存读取(DMA),无须CPU协助即可把数据写入内核缓冲区; 4)内核把数据从内核的临时换冲区拷贝到用户空间的缓冲区,如图所示。整个IO过程总结起来就是两次拷贝
在这里插入图片描述

读如此,写亦然,JVM向磁盘中写数据跟读数据流程相反而已。这里不再累述。

三 系统调用函数read和write的API 详解

1)输入函数read

   Int n_read = read(int fd, char * buf, int n)

参数fd是文件描述符,从命令行读取数据时,设置为0;buf为读缓冲区;n为每次读取到缓冲区的字节数。
当返回值n_read为-1表示读取失败,大于0表示读到缓存区中的字节数。

2)输出函数write

Int n_written = read(int fd, char * buf, int n)

参数fd是文件描述符,输出到命令行时,设置为1;buf为写缓冲区;n为每次写入缓冲区的字节数。
当返回值n_written为-1表示写入失败,大于0表示成功写入字节数。

通过API我们可以发现,虽然两次拷贝降低IO的读写速率,但是我们可以通过提高每次读出或者写入的数据的字节数,有效提高IO的读写速率。

四 IO模型

C语言系统调用函数read和write是同步阻塞的,即代码执行到read或write方法时候,必须执行完当前代码,才能执行下一步。以读数据为例,read(int fd, char * buf, int n)如果用户空间的buf缓冲区没有读取到n个字节,程序就会一直卡在read这个方法,不会往下执行。正因为如此,所以java.io中读写的方法也是同步阻塞的。

五 系统调用代码

root@ubuntu18:~/c_workspace/io#vim read_write_app.c

//在文件中写入如下代码:


```c
#include <unistd.h>

#define MAXSIZE 1024

int main(void){
  char buf[MAXSIZE];
  int n;

  while((n = read(0, buf, MAXSIZE)))
     write(1, buf, n);

  return 0;
}

```bash
#编译成二进制可执行文件
root@ubuntu18:~/c_workspace/io# gcc read_write_app.c -o read_write_app
root@ubuntu18:~/c_workspace/io# ls
read_write_app  read_write_app.c

#与用户交互

第一个hello world!是用户在shell上输入的,第二个是程序将结果写到shell上。

五 参考文献

1) Brian W. Kernighan,Dennis M.Ritchie著,《C语言程序设计》,第二版本,机械工业出版社
2) Andrew S·Tanenbaum 著,《现代操作系统》,第三版本,机械工业出版社

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值