检查使用非阻塞打开时所有数据是否发送完毕
如果我用 os.open( '/dev/ttyS2', O_RDWR | O_NDELAY )
这个命令打开一个文件,有没有办法检查我的 'write()' 命令什么时候完成?或者,我能不能打开一个文件,让读取操作不阻塞,但写入操作是阻塞的?
6 个回答
O_NDELAY这个标志会同时影响读取和写入操作。如果你想在一个非阻塞的文件上进行阻塞写入,可以使用选择(Python模块)来监控这个文件,然后在它变得可以写入的时候进行写入,通常是在一个循环中进行。
如果你在写入一个终端(就像你在例子中做的那样),你可以使用 termios.tcdrain
来等待所有写入的字节都被发送出去。
你的 write
系统调用仍然是非阻塞的,这意味着它不会一直等着完成,所以你需要处理 EWOULDBLOCK
和 EAGAIN
这些错误。同时,你可以使用 select(2)
、poll(2)
或 epoll(7)
来判断什么时候可以向文件描述符写入数据。这些工具都是为了和非阻塞的文件描述符一起使用的。
你对“非阻塞”的理解有些误区。它并不意味着异步操作——你可以有异步/同步和阻塞/非阻塞的任意组合。
一个 write()
操作只是把数据交给内核去处理。当 write()
成功返回时,内核已经处理了这些数据——这和文件描述符是阻塞还是非阻塞没有关系。此时内核是否真的完成了写入是另外一回事(通常答案是“没有”——大多数文件描述符都是异步的)。
如果内核没有足够的空间来缓存你想写入的数据,write()
就无法完成,这就是非阻塞和阻塞的区别所在——在阻塞的情况下,write()
会一直等到有空间可用。而在非阻塞的情况下,write()
会返回一个错误(EAGAIN
),这时就得由你自己决定什么时候重试。
如果你想等到所有写入终端设备的数据实际上都已经发送到硬件,可以使用 tcdrain()
——但这通常是没必要的。或者,如果你希望 write()
在数据被内核接受之前一直阻塞,你可以使用 fcntl()
临时将文件描述符设置为阻塞模式。