linux系统中的IO操作

同步IO分为阻塞IO、非阻塞IO、信号驱动的IO和多路转接IO。

阻塞IO:

一直阻塞进程直到完成IO操作。

非阻塞IO:

有数据时进行IO操作,没有数据时立即返回不阻塞进程。

信号驱动IO:

当有数据到来是发送信号给进程执行IO操作,提高CPU的利用率。当设置打开文件描述字O_ASYNC标志是可以用于信号驱动的IO操作,也可以用过fcntl()改变文件标签,当文件进行IO操作时会产生SIGIO信号或套接字有带外数据到来时会产生SIGURG信号。通过fcntl函数执行F_SETOWN命令可以设置/获得,接收信号的进程/进程组ID。

具体实例:

/*
 * main.c
 *
 *  Created on: 2016年10月22日
 *      Author: chy
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/unistd.h>
#include <termios.h>
#include <signal.h>
#include <sys/fcntl.h>
#include <sys/fcntl.h>
#include <stdio.h>
#include <stdlib.h>

FILE *file;

void sigfunc(int sig)
{
	char c,input[128];
	int n;
	static int i = 0;

	if(read(STDIN_FILENO,&c,1) > 0){
		if(c != '\n')
			input[i++] = c;
		else {
			input[i++] = '\0';
			fprintf(file,"NO sig=%d, input line is %s\n",i,input);
			i = 0;
			 if(c == 'q'){
				 fclose(file);
				 _exit(0);
			 }
		}
	}
}

int main(int argc,char *argv)
{
	int falg;
	char buff[256];
	struct termios newseting,old_termios;
	file = fopen("test.txt","w");
	signal(SIGIO,sigfunc);

	tcgetattr(STDIN_FILENO,&old_termios);
	newseting = old_termios;
	newseting.c_iflag &= (~ICANON);
	newseting.c_cc[VTIME] = 0;
	newseting.c_cc[VMIN] = 1;
	tcsetattr(STDIN_FILENO, TCSANOW, &newseting);
	fcntl(STDIN_FILENO, F_SETOWN,getpid());
	falg = fcntl(STDIN_FILENO, F_GETFL,0);
	falg |= O_ASYNC;
	fcntl(STDIN_FILENO,F_SETFL,falg);
	while(1) sleep(1);

	return 0;
}

多路转接IO:

处理来自多个通道的输入,通过select函数告诉调用它的进程需要等待IO事件的数量。

#include <sys/select.h>
#include <sys/time.h>
int select(int nfds,fd_set *rfds,fd_set *wfds,fd_set *edfs,struct timeval *timeout);
void FD_ZERO(fd_set *fdset); //初始化描述字为空
void FD_CLR(int filedes,fd_set *fdset); //将filedes描述字从fdset描述字集合中清除
int FD_ISSET(int fileds,fd_set *fdset); //判断filedes是否属于fdset所指的描述
void FD_SET(int filedes,fd_set *fdset);  //将filedes添加到描述字fset所指的集合中
select中的三个测试描述字集合都为空可以做为定时器切精度高于sleep。

异步IO :能够在较短时间内从多个接收通道收集大量的数据,异步IO操作在IO期间不阻塞发出IO请求的进程,其IO操作由操作系统派生新的线程并行的执行,当IO操作结束是发送信号给发送请求IO操作的进程通知其IO操作完成,进程也可以调用aio_suspend阻塞进程等待IO操作完成。
#include <aio.h>
int aio_write(struct aiocb *aiocbp);//返回实际写入的字节数
int aio_read(struct aiocb *aiocbp); //返回实际读出的字节数
int lio_listio(int mode,struct aiocb *restrict const list[restrict],int nent,struct sigevent *restrict notification);
int aio_error(struct aiocb *aiocbp); //正在进行IO操作返回EINPROGRESS
ssize_t aio_return(struct aiocb *aiocbp); //返回读写字节个数
int aio_suspend(const struct aiocb *const list[],int nent,const struct timespec *timeout); //挂起调用进程直到IO完成或时间到期
int aio_sysnc(int op,struct aiocb *aiocbp); //把数据同步到物理磁盘

struct aiocb{
     int aio_filds;
     off_t aio_offset;
     volatile void *aio_buf;
     size_t aio_nbytes;
     int aio_reqprio;
     struct sigevent aio_sigevent;
     int aio_lio_opcode;
};

struct sigevent{
     union sigval sigev_value;
     int sigv_signo;
     int sigev_notify;//异步事件的通知类型 SIGEV_NONE(不通知)、SIGEV_SIGNAL(生成信号)、SIGEV_THREAD(执行sigev_notify_function指定的函数)
     void (*sigev_notify_function) (union sigval);
     pthread_attr_t *sigev_notify_attrbutes;
};
具体实例:

/*
 * main.c
 *
 *  Created on: 2016年10月20日
 *      Author: chy
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <sys/unistd.h>
#include <aio.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define buffer_num  2
#define buffer_size 2048
#define ERR(msg,f_num) { \
	if(f_num < 0) { \
		fprintf(stderr,"%s",msg); \
		exit(-1); \
	} \
}

typedef enum{
	buffer_ferr = 1,
	buffer_full,
	buffer_write
}BUFFER;

typedef struct { //缓冲区结构
	BUFFER state;
	int fillpt;
	char buffer[buffer_size];
	struct aiocb aio;
}buffer_t;

static buffer_t buffer[buffer_num];
static sigset_t procmask;
static  int write_num = 0;
static int sig_num;
static volatile off_t seek_ptr;

void sig_func(int signo,siginfo_t *info,void *sig)
{
	int i;
	buffer_t  *temp;

	if(info->si_signo != SIGRTMIN || info->si_code != SI_ASYNCIO)
		return;
	else
		printf("write over\n");
	temp = (buffer_t*)info->si_value.sival_ptr;

	int write_temp_num = 0;
	if(aio_error(&temp->aio) != EINPROGRESS)
		write_temp_num = aio_return(&temp->aio);
	write_num += write_temp_num;
	sig_num++;

	temp->fillpt = 0;
	temp->state = buffer_ferr;
	return;
}

buffer_t *find_empty_buffer()
{
	int i;
	sigset_t newsig;
	sigprocmask(SIG_BLOCK,&procmask,&newsig); //屏蔽异步写信号量

	while(1){
		for(i = 0; i < buffer_num; i++)
			if(buffer[i].state == buffer_ferr)
				break;
		if(i == buffer_num)
			sigsuspend(&procmask); //挂起SIGRTMIN
		else break;
	}
	buffer[i].state = buffer_full;
	buffer[i].fillpt = 0;
	sigprocmask(SIG_SETMASK,&procmask,NULL); //恢复屏蔽异步写信号量
	return (&buffer[i]);
}

void buffer_flush(buffer_t *temp)
{
	temp->aio.aio_offset = seek_ptr; //文件指针的位置
	seek_ptr += temp->fillpt;
	temp->aio.aio_buf = temp->buffer; //缓冲地地址
	temp->aio.aio_nbytes = temp->fillpt; //要传输的字节数
	temp->aio.aio_reqprio = 0;   //优先移位0
	temp->aio.aio_sigevent.sigev_notify = SIGEV_SIGNAL; //实时信号类型
	temp->aio.aio_sigevent.sigev_signo = SIGRTMIN; //信号数
	temp->aio.aio_sigevent.sigev_value.sival_ptr = temp; //携带的信息
	temp->state = buffer_write; //标记为正在写的状态

	ERR("write fail\n",aio_write(&temp->aio));

	return;
}

int main(int argc,char *argv[])
{
	int i,file_in,file_out;
	struct sigaction sig;
	buffer_t *buffer_opt;

	if(argc < 3){
		printf("please input three func\n");
		exit(0);
	}

	file_in = open(argv[1],O_RDONLY);
	ERR("open file_in faile\n",file_in);
	file_out = open(argv[2],O_WRONLY | O_CREAT,0777);
	ERR("open file_out faile\n",file_out);

	for(i = 0; i < buffer_num; i++){
		buffer[i].state = buffer_ferr;
		buffer[i].fillpt = 0;
		buffer[i].aio.aio_fildes = file_out; //绑定文件描述字
	}

	buffer_opt = find_empty_buffer();
	sigemptyset(&procmask);
	sigaddset(&procmask,SIGRTMIN);
	sigemptyset(&sig.sa_mask);
	sig.sa_flags = SA_SIGINFO;
	sig.sa_sigaction = sig_func;

	ERR("sigaction fail\n",sigaction(SIGRTMIN,&sig,NULL));

	int read_num;
	while(1){
		while((read_num = read(file_in,buffer_opt->buffer + buffer_opt->fillpt,buffer_size)) != 0){
			if(read_num > 0){
				buffer_opt->fillpt += read_num;
				if(buffer_opt->fillpt == buffer_size){
					buffer_flush(buffer_opt);
					buffer_opt = find_empty_buffer();
					break;
				}
			}
			if(errno == EINTR)
				break;
			else if(read_num < 0 && errno != EINTR)
				ERR("read faile\n",-1);
		}
	   if(read_num == 0){
			printf("chen\n");
			buffer_flush(buffer_opt);
			break;
		}
	}
	 for(i = 0; i < buffer_num; i++)
		 if(buffer[i].state == buffer_write){
			 struct aiocb *temp[1];
			 temp[0] = &buffer[i].aio;
		     aio_suspend(temp, 1, NULL);
		 }
	 close(file_out);
	 close(file_in);
	 printf("this is over\n");

	 return 1;
}

存储映射IO:传统IO进行读写文件要进行多次系统调用,并且把文件加载到自己的地址空间,其效率低,浪费存储空间。存储映射IO,系统把文件的一页读取到内存,每一个进程把改页映射到自己的内存空间。映射后不再需要read等系统调用,可以通过指令直接访问。存储映射分为共享映射和私有映射,共享映射每个进程都能够改变映射页的内容,当一页被刷新时保回会物理磁盘。私有映射,写文件将导致复制该页的一个副本,物理磁盘物件本身不改变。

#include <sys/mman.h>
void *mmap(void *addr,size_t len,int port,int flags,int filedes,off_t off);
int munmap(void *paddr,size_t len); //删除映射
int msync(void *addr,size_t len,int flags); //写入到物理磁盘
addr:映射区在内存的起始地址。
len:映射的字节数。
prot:映射区的保护权限。
flags:映射区的属性。
filedes: 已打开文件的描述字。
off:文件要映射的其实字节位置。











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值