✍个人博客:https://blog.csdn.net/Newin2020?type=blog
📣专栏地址:https://blog.csdn.net/newin2020/category_12820365.html
📚专栏简介:在这个专栏中,我将会分享 C++ 面试中常见的面试题给大家~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪
📝推荐参考地址:https://www.xiaolincoding.com/(这个大佬的专栏非常有用!)
7. I/O 控制方式
每种设备都有一个设备控制器,控制器相当于一个小 CPU,它可以自己处理一些事情,但有个问题是,当 CPU 给设备发送了一个指令,让设备控制器去读设备的数据,它读完的时候,要怎么通知 CPU 呢?
控制器的寄存器一般会有状态标记位,用来标识输入或输出操作是否完成。于是,我们想到第一种轮询等待的方法,让 CPU 一直查寄存器的状态,直到状态标记为完成,很明显,这种方式非常的傻瓜,它会占用 CPU 的全部时间。
那我们就想到第二种方法 —— 中断,通知操作系统数据已经准备好了。我们一般会有一个硬件的中断控制器,当设备完成任务后触发中断到中断控制器,中断控制器就通知 CPU,一个中断产生了,CPU 需要停下当前手里的事情来处理中断。
另外,中断有两种,一种软中断,例如代码调用 INT 指令触发,一种是硬件中断,就是硬件通过中断控制器触发的。
但中断的方式对于频繁读写数据的磁盘,并不友好,这样 CPU 容易经常被打断,会占用 CPU 大量的时间。对于这一类设备的问题的解决方法是使用 DMA(Direct Memory Access) 功能,它可以使得设备在 CPU 不参与的情况下,能够自行完成把设备 I/O 数据放入到内存。那要实现 DMA 功能要有「DMA 控制器」硬件的支持。
8. DMA 控制方式
DMA 的工作方式如下:
- CPU 需对 DMA 控制器下发指令,告诉它想读取多少数据,读完的数据放在内存的某个地方就可以了;
- 接下来,DMA 控制器会向磁盘控制器发出指令,通知它从磁盘读数据到其内部的缓冲区中,接着磁盘控制器将缓冲区的数据传输到内存;
- 当磁盘控制器把数据传输到内存的操作完成后,磁盘控制器在总线上发出一个确认成功的信号到 DMA 控制器;
- DMA 控制器收到信号后,DMA 控制器发中断通知 CPU 指令完成,CPU 就可以直接用内存里面现成的数据了;
可以看到,CPU 当要读取磁盘数据的时候,只需给 DMA 控制器发送指令,然后返回去做其他事情,当磁盘数据拷贝到内存后,DMA 控制机器通过中断的方式,告诉 CPU 数据已经准备好了,可以从内存读数据了。仅仅在传送开始和结束时需要 CPU 干预。
9. 如果磁盘中有一个文件,此时想要将它读取到内存中,如果使用的是非阻塞 I/O,那这个时候操作系统是如何读取这个文件的?
- 发起非阻塞读取请求:应用程序首先向操作系统发起非阻塞读取请求,请求指定了要读取的文件以及读取的字节数。应用程序不会被阻塞,可以继续执行其他任务。
- 操作系统启动 I/O 操作:操作系统开始执行非阻塞读取操作。它会尝试读取文件的一部分数据(通常是缓冲区大小的一部分),而不会等待数据完全就绪。如果文件中有足够的数据可供读取,操作系统将尽可能多地读取数据,然后返回已读取的字节数。
- 返回读取结果:操作系统将读取的数据传输到应用程序指定的缓冲区,并返回已读取的字节数。如果没有足够的数据可供读取(例如,文件尾部或者暂时没有数据可用),操作系统会返回一个指示当前没有数据可读的状态,而不会阻塞应用程序。
- 应用程序处理结果:应用程序收到操作系统返回的读取结果后,可以根据已读取的数据字节数和数据内容来处理数据。如果还需要继续读取文件的剩余部分,应用程序可以再次发起非阻塞读取请求,然后继续执行其他任务。
- 轮询或事件通知:如果应用程序希望等待更多数据就绪,它可以使用轮询或事件通知机制来检查文件是否有更多数据可读。这允许应用程序不断地检查文件的状态而不阻塞,从而实现非阻塞 I/O。