Linux应用开发之高级IO

提示:


一、阻塞IO与非阻塞IO

对于这两个概念,我是这样的理解的,IO就好比通道,那么阻塞IO就是阻塞的通道,那如果通道被阻塞了,车辆只能停下来休息,那么非阻塞正好相反。

阻塞IO:当资源不可获取时,程序会进入到休眠状态,让出cpu资源,直到资源可以获取才被唤醒
非阻塞IO:不管资源是否可以获取都会立即返回

二、IO多路复用

I/O 多路复用技术是为了解决:在并发式 I/O 场景中进程或线程阻塞到某个 I/O 系统调用而出现的技术,使进程不阻塞于某个特定的I/O 系统调用。监视多路IO

1.select

系统调用 select()可用于执行 I/O 多路复用操作,调用 select()会一直阻塞,直到某一个或多个文件描述
符成为就绪态(可以读或写)

#include <sys/select.h>
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
args:
	nfds:最大文件描述符+1
	readfds:读文件描述符集合
	writefds:写文件描述符集合
	exceptfds:异常文件描述符检测
	timeout:超时时间
return-1:错误
	0:超时
	正数:有一个或多个文件描述符以达到就绪态
#将fd从set中移除
void FD_CLR(int fd, fd_set *set);

int FD_ISSET(int fd, fd_set *set);
#将fd添加进set
void FD_SET(int fd, fd_set *set);
#将set集合清空
void FD_ZERO(fd_set *set);

2.poll

与select类似,在select中有三个fd_set集合,poll中需要构造一个struct pollfd的数组,每个数组指定一个文件描述符

#include <poll.h>

int poll(struct pollfd *fds, nfds_t nfds, int timeout);
args:
	fds:指向struct pollfd类型数组
	nfds:指定fds中元素个数,数据类型nfds_t实际为无符号整型
	timeout:超时
return-1:错误,设置errno
	 0:超时
	 正数:表示fds数组中返回的revents变量不为0struct pollfd对象的数量

三、异步IO

在IO多路复用中,进程通过系统调用select()或者poll()主动查询文件描述符是否可以执行IO操作,而异步IO,当文件描述符可以执行IO操作时,进程可以请求内核为自己发送一个信号。
要使用异步IO,需要满足一下条件:

	1 指定O_NONBLOCK标志
	2 指定O_ASYNC标志 flag | = O_ASYNC
	3 设置异步IO事件的接收进程 fcntl(fd, F_SETOWN, getpid());
	4 设置一个信号处理函数 SIGIO

但事实上SIGIO是是非排队信号,它不支持信号排队机制,比如当前正在执行SIGIO信号处理函数,此时内核又发送多次SIGIO信号给进程,这些信号将会被阻塞,只有当前信号执行完毕之后才会传递给进程,并且只能传递一次,而后续信号都会丢失

使用实时信号替换默认的SIGIO信号

#设置实时信号
fcntl(fd, F_SETSIG, SIGRTMIN);
#绑定信号处理函数
signal(SIGRTMIN, sigrtmin_handler);

使用sigaction()函数注册信号处理函数

#include<signal.h>

int sigaction(int signum,const struct sigaction *act ,struct sigaction *oldact);
struct sigaction {
	void (*sa_handler)(int);
	void (*sa_sigaction)(int, siginfo_t *, void *);
	sigset_t sa_mask;
	int sa_flags; //此参数指定为SA_SIGINFO,表示使用void (*sa_sigaction)(int, siginfo_t *, void *);作为处理函数
	void (*sa_restorer)(void);
};
struct siginfo_t {
	int si_signo;	//引发处理函数被调用的信号。这个值与信号处理函数的第一个参数一致。
	int si_fd;		//表示发生异步 I/O 事件的文件描述符;
	int si_code;	//表示文件描述符 si_fd 发生了什么事件,读就绪态、写就绪态或者是异常事件等。
	int si_band;	//是一个位掩码, 其中包含的值与系统调用 poll()中返回的 revents 字段中的值相同。
};
si_code 		si_band掩码值 						描述/说明
POLL_IN 		POLLIN | POLLRDNORM 				可读取数据
POLL_OUT 		POLLOUT | POLLWRNORM | POLLWRBAND 	可写入数据
POLL_MSG 		POLLIN | POLLRDNORM | POLLMSG 		不使用
POLL_ERR 		POLLERR 							I/O错误
POLL_PRI 		POLLPRI | POLLRDNORM 				可读取高优先级数据
POLL_HUP 		POLLHUP | POLLERR 					出现宕机

四、存储映射IO

存储映射IO是一种基于内存区域的高级IO操作,它可以将一个文件映射到进程地址空间的一块内存区域。

#include <sys/mman.h>

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
args:
	addr:映射起始地址   (系统页大小的整数倍)
	length:映射内存长度
	prot:映射区的保护要求
			PROT_EXEC: 映射区可执行
			PROT_READ: 映射区可读
			PROT_WRITE: 映射区可写
			PROT_NONE: 映射区不可访问
	flags:映射区的属性
			MAP_SHARED: 此标志指定当对映射区写入数据时,数据会写入到文件中,也就是会将写入到映射区中的数据更新到文件中,并且允许其它进程共享
			MAP_PRIVATE: 此标志指定当对映射区写入数据时,会创建映射文件的一个私人副本(copy-onwrite),对映射区的任何操作都不会更新到文件中,仅仅只是对文件副本进行读写
			MAP_ANONYMOUS: 建立匿名映射, 此时会忽略参数 fd 和 offset,不涉及文件,而且映射区域无法和其它进程共享
			MAP_LOCKED: 对映射区域进行上锁
	fd:文件描述符,要映射到内存区域的文件
	offset:文件映射的偏移量 0表示从文件头部开始映射 (系统页大小的整数倍)
	
int munmap(void *addr, size_t length);
#可以更改映射区的保护要求
int mprotect(void *addr, size_t len, int prot);
#刷新内存数据到存储器上
int msync(void *addr, size_t length, int flags);
args:
	flags:MS_ASYNC: 以异步方式进行同步操作。调用 msync()函数之后,并不会等待数据完全写入磁盘之后才返回
		   MS_SYNC: 以同步方式进行同步操作。调用 msync()函数之后,需等待数据全部写入磁盘之后才返回
		   MS_INVALIDATE: 是一个可选标志, 请求使同一文件的其它映射无效

总结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦成大佬的第N天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值