2013-04-20 wcdj
一大早得知四川雅安发生7.0级地震,望灾区的人民尽快得到救助,祈福平安。
问题:
当从一个描述符读,然后又写到另一个描述符时,可以在下列形式的循环中使用阻塞I/O:
while ( (n = read(STDIN_FILENO, buf,BUFSIZ)) > 0 )
{
if( write(STDOUT_FILENO, buf, n) != n )
{
printf("write error\n");
return1;
}
}
但是如果需要从多个描述符读,上面的方法是不行的,如果仍旧使用阻塞I/O,那么就可能长时间阻塞在一个描述符上,而另一个描述符虽有很多数据却不能得到及时处理。针对这个问题,有哪些处理方法呢?
方法1:
用fork将一个进程变成两个进程,每个进程处理一条数据通路,即每个进程都执行阻塞read。
问题是:在进程终止时,使程序变得复杂。
方法2:
使用多线程单进程,这避免了终止的复杂性。
问题是:但却要求处理线程之间的同步,依然没有摆脱复杂性。
方法3:
使用单进程非阻塞I/O读数据,即轮询(polling)的方式。将多个描述符都设置为非阻塞的,对第一个描述符发一个read,如果该输入上有数据,则读数据并处理它;如果无数据可读,则read立即返回。然后对第二个描述符做同样的处理。所有描述符处理完之后,等待若干秒然后再进行轮询。
问题是:浪费CPU时间,因为大多数时间实际是无数据可读的,但仍花费时间不断反复执行read系统调用,在多任务系统中应当避免使用这种方法。
方法4:
异步I/O(asynchronous I/O),其思想是:告知内核启动某个操作,并让内核在整个操作(包括将数据从内核复制到我们自己的缓冲区)完成后通知我们。即,异步I/O模型是由内核通知我们I/O操作合适完成。
问题是:并非所有系统都支持这种机制。
方法5:
使用I/O多路转接(I/Omultiplexing)。先构造一张有关描述符的列表,然后调用一个函数,直到这些描述符中的一个已准备好进行I/O时,该函数才返回,在返回时,此函数告诉进程哪些描述符已准备好可以进行I/O。poll、pselect和select这三个函数使我们能够执行I/O多路转接。即,我们使用select可以等待多个描述符就绪。
PS: 关于I/O复用更多可以参考:
[1] UNPv3第六章
[2] APUEv2 14.5