同步I/O是否会使线程繁忙? [英] Does Synchronous I/O keeps thread busy?

查看:113
本文介绍了同步I/O是否会使线程繁忙?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我正在同步I/O套接字上执行I/O,该套接字已准备好进行readwrite操作.这意味着无论套接字的非阻塞(SOCK_NONBLOCK)/阻塞性质如何,调用线程都不会在该操作上被阻塞.但是我不清楚以下事情-

  1. 何时进行实际转移?将套接字标记为可读取时,内存中是否已经存在数据,或者在调用read命令时会传输数据吗?它是否取决于 socket 的家族?
  2. 如果在读取期间执行数据传输命令,这是否意味着调用线程将繁忙并且延迟取决于套接字硬件?

更新:

使用套接字硬件时,我错了,我在考虑下面的实际数据传输.我知道Socket无关紧要,只是OS中的一个实体,它表示适合通信的文件描述符.

跟进问题-这也意味着在write期间,调用线程将数据写入内存.是否有一个内核线程将负责在套接字的另一侧传输数据?如果是,那么套接字的异步io与同步io有何不同?

解决方案

通常,您可以将套接字I/O视为两级缓冲系统.您的应用程序中有缓冲区,然后有内核缓冲区.因此,当您调用read()时,内核会将数据从内核缓冲区复制到应用程序缓冲区.相应地,当您调用write()时,您正在将数据从应用程序缓冲区复制到内核缓冲区.

然后,内核告诉NIC将传入数据写入内核缓冲区,并从内核缓冲区读取传出数据.该I/O通常是由DMA驱动的AFAIK,这意味着内核只需要告诉NIC该做什么,而NIC负责实际的数据传输.并且当NIC完成时,它将引发一个中断(或者,对于高IO速率,将禁用中断,而是由内核轮询),从而导致接收到该中断的CPU内核停止执行正在执行的任何操作(用户代码,内核代码) (除非禁用了中断,否则将在队列中排队)),然后执行中断处理程序,该处理程序将负责其他需要完成的步骤.

因此,为回答您的后续问题,通常在内核侧没有单独的内核线程处理套接字I/O,工作由NIC硬件并在中断上下文中完成.

对于异步I/O或非阻塞I/O,唯一的区别是如何完成从用户应用程序缓冲区和内核缓冲区的复制.对于非阻塞读取,仅将内核缓冲区中准备好并等待的数据复制到用户空间(这可能会导致短读取),或者如果没有准备好数据,则read()调用将立即使用EAGAIN返回.类似地,对于非阻塞write(),它仅复制与内核缓冲区中可用空间一样多的数据,这可能会导致写入时间短,或者如果根本没有可用空间,则使用EAGAIN返回.对于阻塞的read(),如果没有可用数据,则调用将一直阻塞,直到有可用数据为止;而对于阻塞的write(),如果内核缓冲区已满,则它将进行阻塞,直到有可用空间为止.

Let's say I am doing I/O on a synchronous I/O socket, which is ready for read or write operation. That means that calling thread wouldn't be blocked on the operation, irrespective of the non-blocking(SOCK_NONBLOCK)/blocking nature of the socket. But following things are not clear to me -

  1. When does the actual transfer happen? Is data already present in the memory when the socket is marked ready for reading, or will data be transferred on calling read command? Does it depend on the family of the socket?
  2. If the data transfer is performed during read command, does that mean the calling thread will be busy and the latency will depend on the socket hardware?

Update:

With socket hardware I was wrong, I was thinking about the actual data transfer underneath. I understand that a Socket is not a matter, just an entity in OS to denote a file descriptor fit for communication.

Follow up question - This also means during write, a calling thread writes data into memory. Is there a kernel thread which will take care of transferring data on the other side of the socket? If yes, then how an asyncronous io for sockets is different than the synchronous io?

解决方案

In general you can think of socket I/O as a two level buffering system. There is the buffer in your application, and then there are kernel buffers. So when you call read(), the kernel will copy data from the kernel buffer(s) to your application buffer. Correspondingly, when you call write(), you are copying data from your application buffer to the kernel buffer(s).

The kernel then tells the NIC to write incoming data to the kernel buffers, and read outgoing data from the kernel buffers. This I/O is AFAIK usually DMA-driven, meaning that the kernel just needs to tell the NIC what to do, and the NIC is responsible for the actual data transfer. And when the NIC is finished, it will raise an interrupt (or for high IO rates, interrupts are disabled and the kernel instead polls), causing the CPU core that received the interrupt to stop executing whatever it was executing (user code, kernel code (unless interrupts disabled in which case the interrupt will be queued)) and execute the interrupt handler which then takes care of other steps that need to be done.

So to answer your follow-up question, in general there isn't a separate kernel thread handling socket I/O on the kernel side, work is done by the NIC hardware and in interrupt context.

For asynchronous I/O, or rather non-blocking I/O, the only difference is how the copying from the user application buffer and the kernel buffer(s) is done. For a non-blocking read, only the data that is ready and waiting in the kernel buffers is copied to userspace (which can result in a short read), or if no data is ready the read() call returns immediately with EAGAIN. Similarly, for a non-blocking write(), it copies only as much data as there is available space for in the kernel buffers, which can cause a short write, or if no space is available at all, returning with EAGAIN. For blocking read(), if there is no data available the call will block until there is, whereas for a blocking write(), if the kernel buffer(s) are full, it will block until there is some space available.

这篇关于同步I/O是否会使线程繁忙?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆