(APUE点滴记录) 高级I/O之非阻塞I/O

本文介绍了如何实现非阻塞I/O,包括通过open的O_NONBLOCK标志和fcntl函数设置文件描述符为非阻塞模式。通过测试案例展示了非阻塞I/O在读写大文件时可能遇到的EAGAIN错误,指出这种轮询方式在多用户系统中浪费CPU资源,并提出使用I/O多路转接函数如select和poll作为解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2013-03-30 wcdj

低速系统调用是可能会使进程永远阻塞的一类系统调用,而非阻塞I/O使调用open, read和write这样的I/O操作,并使这些操作不会永远阻塞,如果这种操作不能完成,则调用立即出错返回,表示该操作若继续执行将阻塞。

对于一个给定的描述符有2种方法对其指定为非阻塞I/O:
(1) 如果调用open获得描述符,则可指定O_NONBLOCK标志;
(2) 对于已经打开的一个描述符,则可调用fcntl,由该函数打开O_NONBLOCK文件状态标志;

测试用例:
从STDIN_FILENO标准输入读500K的buffer,设置STDOUT_FILENO为非阻塞I/O,然后将buffer写到标准输出上。
测试1:输出到普通文件
nonblock_write < buffer.txt > out.txt
测试2:输出到终端,并将标准错误信息输出到stderr.out文件
nonblock_write < buffer.txt 2>stderr.out
此时,write有时返回小于500k的一个数字,有时返回出错,errno显示系统调用返回的错误,EAGAIN在Linux上是11,在Max OS X上是35。通过统计,程序发出了数千个write调用,但是只有几百个是真正输出数据的,其余的则出错返回,这种形式的循环称为“轮询”,在多用户系统上它浪费了CPU时间。(对此问题的解决方法是:使用I/O多路转接select和poll函数,以节省CPU的时间)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>

// test buffer is 500M
char buf[500000000];

// flags are file status flags to turn on
void
set_fl(int fd, int flags)
{
	int val;

	if ((val = fcntl(fd, F_GETFL, 0)) < 0)
	{
		printf("fcntl F_GETFL error\n");
		exit(1);
	}

	// turn on flags
	val |= flags;

	if (fcntl(fd, F_SETFL, val) < 0)
	{
		printf("fcntl F_SETFL error\n");
		exit(1);
	}
}

// flags are file status flags to turn off
void
clr_fl(int fd, int flags)
{
	int val;

	if ((val = fcntl(fd, F_GETFL, 0)) < 0)
	{
		printf("fcntl F_GETFL error\n");
		exit(1);
	}

	// turn off flags
	val &= ~flags;

	if (fcntl(fd, F_SETFL, val) < 0)
	{
		printf("fcntl F_SETFL error\n");
		exit(1);
	}
}

int 
main(int argv, char **argc)
{
	int ntowrite, nwrite;
	char *ptr;

	ntowrite = read(STDIN_FILENO, buf, sizeof(buf));
	fprintf(stderr, "read %d bytes\n", ntowrite);

	// set nonblocking
	set_fl(STDOUT_FILENO, O_NONBLOCK);


	// time beg
	time_t beg = time(NULL);

	ptr = buf;
	while (ntowrite > 0)
	{
		errno = 0;

		// it will not block here!
		nwrite = write(STDOUT_FILENO, ptr, ntowrite);
		fprintf(stderr, "nwrite = %d, errno = %d\n", nwrite, errno);

		if (nwrite > 0)
		{
			ptr += nwrite;
			ntowrite -= nwrite;
		}
	}

	// time end 
	time_t end = time(NULL);
	fprintf(stderr, "used time: %lds\n", end - beg);

	// clear nonblocking
	clr_fl(STDOUT_FILENO, O_NONBLOCK);

	return 0;
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值