linux系统中的IO操作

来源:互联网 发布:程序员的职业素养.pdf 编辑:程序博客网 时间:2024/06/02 05:30
同步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操作返回EINPROGRESSssize_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;elseprintf("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); //挂起SIGRTMINelse 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;   //优先移位0temp->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:文件要映射的其实字节位置。











0 0
原创粉丝点击