系统api-高级I/O

非阻塞I/O

(1). open时指定O_NONBLOCK
(2). 对已经打开描述符,调用fcntl打开O_NONBLOCK文件标志。
非阻塞描述符执行io操作,无论操作是否立即完成,均会立即返回.需通过返回结果获知完成情况.

记录/文件范围锁

fcntl记录锁

int fcntl(int fd, 
	// F_GETLK/F_SETLK/F_SETLKW
	// cmd为F_GETLK,参数3-flock*是一个值-结果参数
	int cmd, ...);

struct flock {
	// F_RDLCK/F_WRLCK/F_UNLCK
	short l_type;
	// SEEK_SET/SEEK_CUR/SEEK_END
	short l_whence;
	// start offset
	off_t l_start;
	off_t l_len;
	// 返回持有此锁的进程的ID
	pid_t l_pid;
};

在这里插入图片描述
调用进程已经持有文件A区间A的一个锁后,希望再对文件A区间A加另一个锁,处理方式是直接用新锁替换旧锁(进程对文件A区间A只加一个锁,锁为最后调用fcntl施加的那个).

锁的隐含继承和释放

文件上一个锁信息中包含持有此锁的进程信息
(1). 一个进程终止时,其所持有的文件锁全部释放.
(2). 一个描述符关闭,此进程中基于此描述符所引用文件上的锁自动被释放(注意一个文件即使在同一进程也可被多个描述符引用,这里直接指的是描述符引用的文件).
(3). fork产生的子进程不会继承父进程持有的文件锁,exec产生的有新的执行环境的进程中对之前进程中未关闭的描述符关联的锁会继承.(描述符的执行时关闭标志,意味着exec时,原进程有此标志的描述符会自动关闭,再执行新的执行环境的进程).

FreeBSD

记录锁通过文件+进程来标识.
在这里插入图片描述在这里插入图片描述
上述在父进程中,关闭fd1,fd2fd3任一个,都将释放由父进程设置的写锁.

在文件尾端加锁

在这里插入图片描述在这里插入图片描述

上面假设首个write执行时,文件位置在尾部,如希望解除追加的第一个字节的锁,un_lock应在参数2传入-1来找到正确位置(文件尾/当前位置随着文件读写而动态变化).

建议性锁和强制性锁

(1). 所谓建议性锁指的是,我们通过fcntl对文件A区域A1进行加锁.
后续其他进程对文件A区域A1进行fcntl时,会参考此区域已经加锁信息来决定操作是否可行.其他进程若未执行fcntl,直接对文件A区域A1执行read/write则,此区域已经加锁信息,对read/write无影响.
(2). 所谓强制性锁指的是,我们通过fcntl对文件A区域A1进行加锁.
后续其他进程对文件A区域A1进行read/write/open/fcntl时均要参考此区域已经加锁信息来决定操作是否可行.
(3). 强制性锁对应于互斥锁
适合于所有使用锁定文件的用户均遵循一致的规则,即访问文件前,先进行锁定,再访问,访问后释放锁定的模式来进行进程间资源共享.
在这里插入图片描述

I/O多路转接

select

// < 0/=0/>0 数值是3个集合中准备好描述符个数之和
int select(
	// 三个描述符集合中最大描述符+1
	int maxfdp1, fd_set *restrict readfds, 
	fd_set *restrict writefds, fd_set *restrict exceptfds,
	// (1).NULL:
	// 直到某些描述符已经准备好
	// (2).字段tv_sec,tv_usec均为0:
	// 立即返回
	// (3).有效数值:
	// 指定等待时间
	struct timeval *restrict tvptr);// 秒和微秒

在这里插入图片描述

int FD_ISSET(int fd, fd_set* fdset);
void FD_CLR(int fd, fd_set* fdset);
void FD_SET(int fd, fd_set* fdset);
void FD_ZERO(fd_set* fdset);

基于比特位管理,若windows上一般只支持数值在1024之内的描述符使用.

poll

int poll(
	struct pollfd fdarray[],
	nfds_t nfds,
	// -1/0/>0
	int nsecs);
	
struct pollfd
{
	int fd;
	short events;
	short revents;
};

在这里插入图片描述
基于数组.

异步I/O

POSIX异步I/O

// 异步I/O控制块
// 异步I/O操作必须显式地指定偏移量
// 异步I/O接口并不影响由操作系统维护的文件偏移量
// 如果用异步I/O向以追加模式打开的文件写数据,aio_offset被忽略
struct aiocb
{
	int aio_fildes;
	off_t aio_offset;
	volatile void *aio_buf;
	size_t aio_nbytes;
	// priority
	int aio_reqprio;
	// 在I/O事件完成后,如何通知应用。
	struct sigevent aio_sigevent;
	int aio_lio_opcode;
};

struct sigevent
{
	/*SIGEV_NONE:不通知进程*/ 	
	/*SIGEV_SIGNAL:产生由sigev_signo字段指定的信号。
	如支持排队信号,且建立信号处理时指定了SA_SIGINFO,则信号入队,
	信号处理程序传送一个siginfo结构,字段si_value为sigev_value。*/ 
	/*SIGEV_THREAD:sigev_notify_function指定的函数被调用,sigev_value作为参数传给函数。
	除非sigev_notify_attributes字段被设为pthread属性结构的地址,
	且该结构指定了一个另外的线程属性,否则该函数将在分离状态下的一个单独线程中执行。*/ 
	int sigev_notify;
	int sigev_signo;
	union sigval sigev_value;
	void (*sigev_notify_function)(union sigval);
	pthread_attr_t *sigev_notify_attributes;
};

int aio_read(struct aiocb *aiocb);
int aio_write(struct aiocb *aiocb);
// op设为O_DSYNC,则类似fdatasync
// op设为O_SYNC,则类似fsync
int aio_fsync(int op, struct aiocb* aiocb);
// 0				异步操作完成,需调用aio_return获取返回值
// -1				对aio_error调用失败。errno告知原因。
// EINPROGRESS		异步读,写或同步操作仍在等待
// 其他				
int aio_error(const struct aiocb* aiocb);
ssize_t aio_return(const struct aiocb* aiocb);
int aio_suspend(const struct aiocb *const list[], int nent, const struct timespec *timeout);
int aio_cancel(int fd, struct aiocb *aiocb);
int lio_listio(
	// 如为LIO_WAIT,在所有指定的I/O操作完成后返回。
	// 这时,sigev将被忽略。
	// 如为LIO_NOWAIT,立即返回。
	// 进程将在所有I/O操作完成后,按sigev参数指定的,被异步地通知。
	// 如不想被通知,可把sigev设为NULL。
	// 每个AIO控制块本身也可能启用了在各自操作完成时的异步通知。
	// AIO控制块中,aio_lio_opcode定操作类型LIO_READ/LIO_WRITE/LIO_NOP
	int mode, struct aiocb *restrict const list[restrict],
	int nent, struct sigevent *restrict sigev);

在这里插入图片描述

readv和writev

ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
struct iovec
{
	// 缓存开始地址
	void *iov_base;
	// 缓存大小
	size_t iov_len;
};

存储映射I/O

void* mmap(void* addr, size_t len,
	// PROT_READ/PROT_WRITE/PROT_EXEC/PROT_NONE.但保护要求不能超过文件open模式访问权限
	int prot,
	// MAP_FIXED,返回值需要等于addr。未指定时,即使addr有值,也仅是一个建议值
	// MAP_SHARED/MAP_PRIVATE
	int flag, int fd, off_t off);
int mprotect(
	// 需为系统页长倍数
	void *addr, size_t len, int prot);
// 共享映射的内存区域对虚拟内存区域的写直接写到关联的磁盘文件.
// 对所有共享映射进程可见.此调用让内存修改页立即写回磁盘
int msync(
	void *addr, size_t len,
	// 二选一
	// MS_ASYNC
	// MS_SYNC	
	int flags);
int munmap(void *addr, size_t len);

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

raindayinrain

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

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

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

打赏作者

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

抵扣说明:

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

余额充值