文件I/O编程
一、系统调用
所谓的系统的调用时操作系统提供给用户程序调用的一组“特殊”接口,用户可以同个接口获得系统提供的服务。例如用户通过系统调用可以实现创建进程、进程的管理、soket网络通信。
linux用户程序是不能直接访问系统内核提供的服务的。这样做是为了保护系统内核的数据不被修改,保证了系统的安全性。用户空间和内核空间是分离的,通常情况下用户程序不允许访问内核数据和内核的函数。
二、用户编程接口(API)
前面写到用户不是直接和系统进行交互的,而是通过软中断机制向内核提出申请,以获取内核服务的接口。在实际编程中用户调用的是API函数。并不是一个API对应一个系统调用,有的时候一个API 函数对应几个系统的调用。
三、系统命令
系统命令相对于API更高了一层,它实际 上是一个可执行的程序。它们三者之间的关系如下图:
四、linux文件及文件描述符
在linux学习中很重要的一点就是所有的操作都是对文件的操作,内核区分文件就是通过文件描述符。文件描述符是一个非负的整数,它是一个索引值,指向内核中每个进程打开文件的记录表。当打开一个现存文件或新建一个文件时,就会返回一个文件描述符;当读写文件时,也需要将文件描述符作为参数传递给函数。
通常一个进程启动时,会打开三个文件:标准输入,标准输出,标准出错处理。这三个文件分别对应文件描述符0,1,2.(也就是宏替换STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO).
五、不带缓存的I/O操作
下面的第一个程序是向一个文件中写入字符,并按照指定的字节读出来。调用了write、open和read函数。
六、fcntl函数
当多个 用户共同使用和操作一个文件时,为了避免出错和进程竞争资源的问题,linux采用给文件上锁的方式。实现上锁的函数式lock和fcntl。其中flock对文件施加建议锁。而fcntl不仅可以施加建议性锁还可以施加强制性锁。同时fcntl还可以对文件上记录锁。
记录锁又分为读取锁和写入锁,其中读取锁又称为共享锁,它能使多个进程在同一时刻对文件建立读取锁。写入锁又称为排斥锁,在任意时刻只有一个进程可以对文件的某一部分施加写入锁。当然,在文件的同一部分不能同时建立写入锁和读取锁。
下面是测试文件的写入锁,首先创建一个hello文件,然后加上写入锁,写入之后释放写入锁。
终端2运行的结果:
七、总的来说I/O处理的模型有5种。
1、阻塞I/O模型:在这种模型下,若所调用的I/O函数没有完成相关的功能,就会将进程挂起,直到相关数据到才会出错返回。如常见的对管道设备、终端设备和网络设备进行读写时就会经常出现这种问题。
2、非阻塞模型:这种模型下,当情求的I/O不能完成时,则不让进程睡眠,而是返回一个错误。
3、I/O多路转接模型:在这种模型下,如果请求的I/O阻塞,且它不是真正的阻塞,而是让其中的一个函数等待,在这期间,I/O还能继续其他的操作。select函数就是属于这种模型。
4、信号驱动I/O模型:在这种模型下,通过安装一个信号处理程序,系统可以自动捕获特定信号的到来,从而启动I/O。这是由内核通知用户何时何时启动I/O操作。
5、异步I/O模型:在这种模型下,当一个描述符已经准备好,可以启动I/O时,进程会通知内核。现在,并不是所有的内核都支持这种模型。
可以看到select的多路转接模型是处理I/O复用的一个高效的方式。它可以具体设置每一个具体所关心的文件描述符的条件、等待的时间。
本例中是将hello1的内容读出,并将此内容每隔10秒写入hello2中。在这里建立了两个描述符集,其中一个描述符inset1用于读取文件,另一个inset2用于写文件。在初始化文件描述符之后,就循环的测试这两个文件是否可读写,由于这里没有阻塞,所以文件描述符处于准备就绪状态。这时对两个描述符进行fds[0]和fds[1]进行读写操作。
程序运行的流程:
版权所有,属于华清远见。