第14章 高级I/O

1. 非阻塞I/O

对于一个给定的描述符,有两种为其指定非阻塞I/O的办法:

i. 如果调用open获得描述符,则可制定O_NONBLOCK标志;

ii. 对于已经打开的一个描述符,则可调用fcntl,由该函数打开O_NONBLOCK文件状态标志。

<span style="font-size:18px;">#include "apue.h"
#include <errno.h>
#include <fcntl.h>

char buf[500000];

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

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

	set_fl(STDOUT_FILENO, O_NONBLOCK); //set nonblocking

	ptr = buf;
	while(ntowrite > 0){
		errno = 0;
		nwrite = write(STDOUT_FILENO, ptr, ntowrite);
		fprintf(stderr, "nwrite = %d, errno = %d\n", nwrite, errno);

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

	clr_fl(STDOUT_FILENO, O_NONBLOCK); //clear nonblocking

	exit(0);
}</span>

2. 记录锁

i. fcntl记录锁

如果在一个给定字节上已经有一把或多把读锁,则不能在该字节上再加写锁;如果在一个字节上已经有一把独占性写锁,则不能再对它加任何锁。

<span style="font-size:18px;"><span style="font-size:18px;">#include "apue.h"
#include <fcntl.h>

static void lockabyte(const char *name, int fd, off_t offset)
{
	if(writew_lock(fd, offset, SEEK_SET, 1) < 0)
		err_sys("%s: writew_lock error", name);
	printf("%s: got the lock, byte %lld\n", name, (long long)offset);
}

int main(void)
{
	int fd;
	pid_t pid;

	//create a file and write two bytes in it
	if((fd = creat("templock", FILE_MODE)) < 0)
		err_sys("creat error");
	if(write(fd, "ab", 2) != 2)
		err_sys("write error");

	TELL_WAIT();
	if((pid = fork()) < 0){
		err_sys("fork error");
	} else if(pid == 0){
		lockabyte("child", fd, 0);
	//	sleep(2);
		TELL_PARENT(getppid());
		WAIT_PARENT();
		lockabyte("child", fd, 1);
	} else{
	//	sleep(5);
		lockabyte("parent", fd, 1);
	//	sleep(5);
		TELL_CHILD(pid);
		WAIT_CHILD();
		lockabyte("parent", fd, 0);
	}
	exit(0);
}
/**************************************************
child: got the lock, byte 0
parent: got the lock, byte 1
child: writew_lock error: Resource deadlock avoided
parent: got the lock, byte 0
**************************************************/
</span></span>

ii. 锁的隐含继承和释放

关于记录锁的自动继承和释放有3条规则

锁与进程与文件相关联;由fork产生的子进程不继承父进程所设置的锁;在执行exec之后,新程序可以继承原执行程序的锁。

iii. 建议性锁和强制性锁

建议性锁并不能阻止对数据库文件有写权限的任何其他进程写这个数据库文件;强制性锁会让内核检查每一个open,read和write,验证调用进程是否违背正在访问的文件上的一把锁。

<span style="font-size:18px;"><span style="font-size:18px;">#include "apue.h"
#include <errno.h>
#include <fcntl.h>
#include <sys/wait.h>

int main(int argc, char *argv[])
{
	int fd;
	pid_t pid;
	char buf[5];
	struct stat statbuf;

	if(argc != 2){
		fprintf(stderr, "usage: %s filename\n", argv[0]);
		exit(1);
	}
	if((fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, FILE_MODE)) < 0)
		err_sys("open error");
	if(write(fd, "abcdef", 6) != 6)
		err_sys("write error");

	//turn on set-group-ID and turn off group-execute
	if(fstat(fd, &statbuf) < 0)
		err_sys("fstat error");
	if(fchmod(fd, (statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0)
		err_sys("fchmod error");

	TELL_WAIT();

	if((pid = fork()) < 0)
		err_sys("fork error");
	else if(pid > 0){
		//write lock entire file
		if(write_lock(fd, 0, SEEK_SET, 0) < 0)
			err_sys("write_lock error");

		TELL_CHILD(pid);

		if(waitpid(pid, NULL, 0) < 0)
			err_sys("waitpid error");
	}
	else{
		WAIT_PARENT();
		set_fl(fd, O_NONBLOCK);

		if(read_lock(fd, 0, SEEK_SET, 0) != -1)
			err_sys("child: read_lock succeeded");
		printf("read_lock of already-locked region returns %d\n", errno);
		if(lseek(fd, 0, SEEK_SET) == -1)
			err_sys("lseek error");
		if(read(fd, buf, 2) < 0)
			err_ret("read failed (mandatory locking works)");
		else
			printf("read OK (no mandatory locking), buf = %2.2s\n", buf);
	}
	exit(0);
}
/********************************************
read_lock of already-locked region returns 11
read OK (no mandatory locking), buf = ab
********************************************/
</span></span><pre name="code" class="cpp"><span style="font-size:18px;">#include "apue.h"

ssize_t readn(int fd, void *ptr, size_t n)
{
	size_t nleft;
	ssize_t nread;

	nleft = n;
	while(nleft > 0){
		if((nread = read(fd, ptr, nleft)) < 0){
			if(nleft == n)
				return -1;
			else
				break;
		} else if(nread == 0){
			break;
		}
		nleft -= nread;
		ptr += nread;
	}
	return n - nleft;
}

ssize_t writen(int fd, void *ptr, size_t n)
{
	size_t nleft;
	ssize_t nwrite;
	nleft = n;

	while(nleft > 0){
		if((nwrite = write(fd, ptr, nleft)) < 0){
			if(nleft == n)
				return -1;
			else
				break;
		}
		else if(nwrite == 0){
			break;
		}
		nleft -= nwrite;
		ptr += nwrite;
	}
	return n - nleft;
}
</span>

3. I/O多路选择

i. select函数和pselect函数

int select(int maxfdp1, fd_set *restrict readfds, fd_set *restrict writefds, fe_set *restrict exceptfds, struct timeval *restrict tvptr); //返回准备就绪的描述符数;若超时,返回0;若出错,返回-1。

tvptr = NULL,永远等待; tvptr->tv_sec = 0 && tvptr->tv_usec == 0,不等待;当有具体值时,等待具体的时间。

对描述符集的处理和判断

int FD_ISSET(int fd, fd_set *fdset); //判断是否在描述符集中,在的话,返回非0;

int FD_CLR(int fd, fd_set *fdset); //清除描述符集的某一位

int FD_SET(int fd, fd_set *fdset); //开启描述符集的某一位

int FD_ZERO(fd_set *fdset); //把描述符集的每一位都清空

int pselect(int maxfdp1, fd_set *restrict readfds, fd_set *restrict writefds, fe_set *restrict exceptfds, const struct timespec *restrict tsptr, const sigset_t *restrict sigmask); //返回准备就绪的描述符数;若超时,返回0;若出错,返回-1。

ii. poll函数

int poll(struct pollfd fdarray[], nfds_t nfds, int timeout); //返回值的意义跟select一样

timeout = -1, 永远等待;timeout = 0,不等待;有具体值时,等待该值的毫秒数

4. 异步I/O

POSIX的异步I/O(???)

5. readv函数和writev函数

ssize_t readv(int fd, const struct iovec *iov, int iovcnt);

ssize_t writev(int fd, const struct iovec *iov, int iovcnt);

//作用:在一次函数调用中读写多个非连续缓冲区

6. readn函数和writen函数

ssize_t readn(int fd, void *buf, size_t nbytes);

ssize_t writen(int fd, void *buf, size_t nbytes);

//分别读写指定的N字节数据,并处理返回值小于要求值的情况;

<span style="font-size:18px;">#include "apue.h"

ssize_t readn(int fd, void *ptr, size_t n)
{
	size_t nleft;
	ssize_t nread;

	nleft = n;
	while(nleft > 0){
		if((nread = read(fd, ptr, nleft)) < 0){
			if(nleft == n)
				return -1;
			else
				break;
		} else if(nread == 0){
			break;
		}
		nleft -= nread;
		ptr += nread;
	}
	return n - nleft;
}

ssize_t writen(int fd, void *ptr, size_t n)
{
	size_t nleft;
	ssize_t nwrite;
	nleft = n;

	while(nleft > 0){
		if((nwrite = write(fd, ptr, nleft)) < 0){
			if(nleft == n)
				return -1;
			else
				break;
		}
		else if(nwrite == 0){
			break;
		}
		nleft -= nwrite;
		ptr += nwrite;
	}
	return n - nleft;
}
</span>

7. 存储映射I/O

能将一个磁盘文件映射到存储空间中的一个缓冲区上,当从缓冲区读取数据时,就相当于读文件中的字节。(在不使用read和write的情况下执行I/O)

void *mmap(void *addr, size_t len, int port, int flag, off_t off); //若成功返回映射区的起始地址;若出错返回MAP_FAILED

//mprotect可以更改一个现有映射的权限

int mprotect(void *addr, size_t len, int prot);

int msync(void *addr, size_t len, int prot); //如果共享映射中的页已修改,那么可以调用msync将该页冲洗到被映射的文件中

int munmap(void *addr. size_t len); //解除映射区

#include <fcntl.h>
#include <sys/mman.h>

#define COPYINCR (1024 * 1024 * 1024)

int main(int argc, char *argv[])
{
	int fdin, fdout;
	void *src, *dst;
	size_t copysz;
	struct stat sbuf;
	off_t fsz = 0;

	if(argc != 3)
		err_quit("usage:  %s <fromfile> <tofile>", argv[0]);

	if((fdin = open(argv[1], O_RDONLY)) < 0)
		err_sys("can't creat %s for reading", argv[1]);

	if((fdout = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, FILE_MODE)) < 0)
		err_sys("can't creat %s for writing", argv[2]);

	if(fstat(fdin, &sbuf) < 0)
		err_sys("fstat error");

	if(ftruncate(fdout, sbuf.st_size) < 0)
		err_sys("ftruncate error");

	while(fsz < sbuf.st_size){
		if((sbuf.st_size - fsz) > COPYINCR)
			copysz = COPYINCR;
		else
			copysz = sbuf.st_size - fsz;

		if((src = mmap(0, copysz, PROT_READ, MAP_SHARED, fdin, fsz)) == MAP_FAILED)
			err_sys("mmap error for input");
		if((dst = mmap(0, copysz, PROT_READ | PROT_WRITE, MAP_SHARED, fdout, fsz)) == MAP_FAILED)
			err_sys("mmap error for output");

		memcpy(dst, src, copysz);
		munmap(src, copysz);
		munmap(dst, copysz);
		fsz += copysz;
	}
	exit(0);
}
时间: 2024-08-29 06:44:46

第14章 高级I/O的相关文章

apue读书笔记-第14章 高级IO

多路I/O转接 与select函数不同,poll不是为每个状态(可读性.可写性和异常状态)构造一个描述符集,而是构造一个pollfd结构数组,每个数组元素指定一个描述符编号以及其所关心的状态 readv和writev函数 作用:在一次函数调用中读.写多个非连续缓存区 总结:应当用尽量少的系统调用次数来完成任务.如果只写少量的数据,会发现自己复制数据然后使用一次write会比用writev更合算.但也可能发现,这样获得的性能提升并不值得,因为管理中间缓冲区会增加程序复杂度. readn和write

第14章 高级路由特性

---------------------------------------------------------- 原则:1.应该首先定义最具体的路由.  2.建议为URL模式中的所有片段变量都提供值. 注意:1.Html.ActionLink在匹配时,前有打断原则(前面提供值后,后面的变量必须提供值,打断默认值链)  @Html.RouteLink方法,指定一条路由生成链接(路由name)  2.在参数传递给ActionLink方法时,注意将其余变量值传递null.  3.在区域下面的Web

apue 第14章 高级I/O

1.引言 2.非阻塞I/O 系统调用分为两类:低速系统调用和其他. 低速系统调用是可以使进程永远阻塞的一类系统调用 如果某些文件类型(读管道.终端设备和网络设备)的数据并不存在,读操作可能会使调用者永远阻塞 如果数据不能被相同的文件类型立即接受(管道中无空间.网络流控制).写操作可能会使调用者永远阻塞 在某种条件发生之前打开某些文件类型可能会发生阻塞 对已经加上强制性记录锁的文件进行写 某些ioctl操作 某些进程间通信函数 非阻塞I/O使我们可以发出open,read和write这样的I/O操

JavaScript高级程序设计(第三版)学习笔记13、14章

第13章,事件 事件冒泡 IE的事件叫做事件冒泡:由具体到不具体 <!DOCTYPE html> <html> <head> <title>Event Bubbling Example</title> </head> <body> <div id="myDiv">Click Me</div> </body> </html> 如果你单击了<div>

第 14 章 迭代器模式【Iterator Pattern】

以下内容出自:<<24种设计模式介绍与6大设计原则>> 周五下午,我正在看技术网站,第六感官发觉有人在身后,扭头一看,我C,老大站在背后,赶忙站起来, “王经理,你找我?” 我说. “哦,在看技术呀.有个事情找你谈一下,你到我办公室来一下.” 老大说. 到老大办公室, “是这样,刚刚我在看季报,我们每个项目的支出费用都很高,项目情况复杂,人员情况也不简单,我看着 也有点糊涂,你看,这是我们现在还在开发或者维护的103 个项目,你能不能先把这些项目信息重新打印一份 给我,咱们好查查到

第六章 高级加密标准

第六章 高级加密标准 美国国家技术研究所NIST在2001年发布了高级加密标准AES,一个对称分组密码算法,取代DES称为广泛使用的标准. 与公钥密码RSA相比,AES以及大多数的对称密码的结构都很复杂. AES中所有的运算是在8位的字节上进行的. 一个域是一个结合,在集合内进行加减乘除运算的结果,也不会离开该域.例如\(Z_p=\{0,1,2,3,\dots,p-1\}\),其中\(p\)是一个素数,然后该域上的操作是取模. 1. AES的结构 明文分组长度为128位即16字节(对明文进行分组

《TCP/IP详解卷1:协议》第14章 DNS:域名系统---读书笔记

<TCP/IP详解卷1:协议>第14章 DNS:域名系统---读书笔记 1.引言 5.指针查询 DNS中一直难于理解的部分就是指针查询方式,即给定一个IP地址,返回与该地址对应的域名. 当一个组织加入Internet,并获得DNS域名空间的授权,如noao.edu,则它们也获得了对应IP地址的in-addr.arpa域名空间的授权.在noao.edu这个例子中,它的网络号是140.252的B类网络.在DNS树中结点in-addr.arpa的下一级必须是该IP地址的第一字节(例中为140),再下

&lt;&lt;精通iOS开发&gt;&gt;第14章例子代码小缺陷的修复

大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 首先推荐大家看这本书,整本书逻辑非常清晰,代码如何从无到有,到丰满说的很有条理. 说实话本书到目前为止错误还是极少的,不过人无完人,在第14章前半部分项目的代码中,作者在MasterVC到DetailVC中又直接添加了一个segue,该segue的ID为"masterToDetail",作用是当新建一个tinyPix文档时可以直接跳转到DetailV

Java 线程第三版 第六章 高级同步议题 读书笔记

多线程数据同步错误比较难检测,因为通常是与事件的特定发生顺序有关. 一.同步术语 Barrier(屏障) barrier是多个Thread的集合点:所有的Thread都应该到齐在这个barrier之后才能允许它们继续下去. Condition variable(条件变量) 实际上不是变量,而是与某个lock有关联的变量. Event variable(事件变量) 条件变量的另一个名称. Critical section(临界区) 临界区是synchronized方法或者block. Lock(锁