当前位置: 首页 > news >正文

Linux IO模型:阻塞IO、非阻塞IO、IO多路复用、信号驱动IO、异步IO

1. 阻塞IO

最简单直接的IO模型。

调用过程:

进程调用recvfrom系统调用,进程阻塞;等待数据,数据准备完成,

将数据从内核拷贝到用户空间,系统调用返回;进程继续处理。
在这里插入图片描述
优点是简单直接,缺点是进程阻塞,浪费资源。

2. 非阻塞IO

非阻塞IO采用轮询的方式隔一段时间发起系统调用看数据是否就绪,

与阻塞IO不同的是它会马上返回结果。

如果数据准备就绪,就将数据拷贝到用户空间,返回成功。

否则kernal立即返回EWOUDBLOCK这个错误。

因此在准备数据阶段,不会阻塞进程。

优点:进程发起I/O操作时,不会因为数据未就绪而阻塞。

缺点:会多次调用系统调用,消耗CPU。

在这里插入图片描述

3. I/O多路复用

I/O多路复用可以理解为,单线程监听多个文件描述符。

I/O多路利用向kernel发起系统调用(select、poll、epoll)

传入文件描述符和相应的动作read、writekernel去监测,当

其中有文件描述有相应的动作发生,就返回结果。进程再

发起真正的I/O操作。

在这里插入图片描述

4. 信号驱动IO

通过信号来通知数据是否到来,

因此在等待数据到来这个阶段进程不会阻塞。

在信号触发后,调用相应的信号处理函数,开始真正的I/O操作:

将数据从内核拷贝到用户空间,这时候进程会阻塞。

在这里插入图片描述

下面是找得一段例子,sigaction对信号绑定相应的处理函数,相应的处理

函数就是sa.sa_handler

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <signal.h>
#include <errno.h>#include <linux/if_tun.h>extern int errno;int bridge_term = 0;
int f1, f2;void sig_io(int sig) 
{static char buf[1600];register int r;while( (r=read(f1, buf, sizeof(buf))) > 0 )write(f2, buf, r);if( r < 0 && (errno != EAGAIN && errno != EINTR) ) {bridge_term = 1;return;}while( (r=read(f2, buf, sizeof(buf))) > 0 )write(f1, buf, r);if( r < 0 && (errno != EAGAIN && errno != EINTR) ) {bridge_term = 1;return;}
}int main(int argc, char *argv[])
{struct sigaction sa;char buf[20];if(argc < 2) {printf("Usage: bridge tap|tun\n");exit(1);}sprintf(buf,"/dev/%s%d",argv[1],0);f1 = open(buf, O_RDWR);sprintf(buf,"/dev/%s%d",argv[1],1);f2 = open(buf, O_RDWR);ioctl(f1, TUNSETNOCSUM, 1);ioctl(f2, TUNSETNOCSUM, 1);fcntl(f1, F_SETFL, O_NONBLOCK | O_ASYNC);fcntl(f2, F_SETFL, O_NONBLOCK | O_ASYNC);memset(&sa, 0, sizeof(sa));sa.sa_handler = sig_io;sigaction(SIGIO, &sa, NULL); while( !bridge_term )sleep(1000); 
}

5. 异步I/O

在异步I/O中,I/O操作不会引起进程的阻塞。等待数据和拷贝数据都发生在了内核之中。数据就绪后,发送一个signal到进程中去,进程再进行处理。

在这里插入图片描述

下面给出posix aio的一个例子

先给出aiocb的结构体定义

struct aiocb
{int aio_fildes;		/* File descriptor.  */int aio_lio_opcode;		/* Operation to be performed.  */int aio_reqprio;		/* Request priority offset.  */volatile void *aio_buf;	/* Location of buffer.  */size_t aio_nbytes;		/* Length of transfer.  */struct sigevent aio_sigevent;	/* Signal number and value.  *//* Internal members.  */struct aiocb *__next_prio;int __abs_prio;int __policy;int __error_code;__ssize_t __return_value;#ifndef __USE_FILE_OFFSET64__off_t aio_offset;		/* File offset.  */char __pad[sizeof (__off64_t) - sizeof (__off_t)];
#else__off64_t aio_offset;		/* File offset.  */
#endifchar __glibc_reserved[32];
};

再给出示例程序,主要是用aio从文件中进行读取。

我们可以运行

./a.out /dev/stdin /dev/stdin

来观察程序运行的结果。

       #include <fcntl.h>#include <stdlib.h>#include <unistd.h>#include <stdio.h>#include <errno.h>#include <aio.h>#include <signal.h>#define BUF_SIZE 20     /* Size of buffers for read operations */#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)struct ioRequest {      /* Application-defined structure for trackingI/O requests */int           reqNum;int           status;struct aiocb *aiocbp;};static volatile sig_atomic_t gotSIGQUIT = 0;/* On delivery of SIGQUIT, we attempt tocancel all outstanding I/O requests */static void             /* Handler for SIGQUIT */quitHandler(int sig){gotSIGQUIT = 1;}#define IO_SIGNAL SIGUSR1   /* Signal used to notify I/O completion */static void                 /* Handler for I/O completion signal */aioSigHandler(int sig, siginfo_t *si, void *ucontext){if (si->si_code == SI_ASYNCIO) {write(STDOUT_FILENO, "I/O completion signal received\n", 31);/* The corresponding ioRequest structure would be available asstruct ioRequest *ioReq = si->si_value.sival_ptr;and the file descriptor would then be available viaioReq->aiocbp->aio_fildes */}}intmain(int argc, char *argv[]){struct sigaction sa;int s;int numReqs;        /* Total number of queued I/O requests */int openReqs;       /* Number of I/O requests still in progress */if (argc < 2) {fprintf(stderr, "Usage: %s <pathname> <pathname>...\n",argv[0]);exit(EXIT_FAILURE);}numReqs = argc - 1;/* Allocate our arrays. */struct ioRequest *ioList = calloc(numReqs, sizeof(*ioList));if (ioList == NULL)errExit("calloc");struct aiocb *aiocbList = calloc(numReqs, sizeof(*aiocbList));if (aiocbList == NULL)errExit("calloc");/* Establish handlers for SIGQUIT and the I/O completion signal. */sa.sa_flags = SA_RESTART;sigemptyset(&sa.sa_mask);sa.sa_handler = quitHandler;if (sigaction(SIGQUIT, &sa, NULL) == -1)errExit("sigaction");sa.sa_flags = SA_RESTART | SA_SIGINFO;sa.sa_sigaction = aioSigHandler;if (sigaction(IO_SIGNAL, &sa, NULL) == -1)errExit("sigaction");/* Open each file specified on the command line, and queuea read request on the resulting file descriptor. */for (size_t j = 0; j < numReqs; j++) {ioList[j].reqNum = j;ioList[j].status = EINPROGRESS;ioList[j].aiocbp = &aiocbList[j];ioList[j].aiocbp->aio_fildes = open(argv[j + 1], O_RDONLY);if (ioList[j].aiocbp->aio_fildes == -1)errExit("open");printf("opened %s on descriptor %d\n", argv[j + 1],ioList[j].aiocbp->aio_fildes);ioList[j].aiocbp->aio_buf = malloc(BUF_SIZE);if (ioList[j].aiocbp->aio_buf == NULL)errExit("malloc");ioList[j].aiocbp->aio_nbytes = BUF_SIZE;ioList[j].aiocbp->aio_reqprio = 0;ioList[j].aiocbp->aio_offset = 0;ioList[j].aiocbp->aio_sigevent.sigev_notify = SIGEV_SIGNAL;ioList[j].aiocbp->aio_sigevent.sigev_signo = IO_SIGNAL;ioList[j].aiocbp->aio_sigevent.sigev_value.sival_ptr =&ioList[j];s = aio_read(ioList[j].aiocbp);if (s == -1)errExit("aio_read");}openReqs = numReqs;/* Loop, monitoring status of I/O requests. */while (openReqs > 0) {sleep(3);       /* Delay between each monitoring step */if (gotSIGQUIT) {/* On receipt of SIGQUIT, attempt to cancel each of theoutstanding I/O requests, and display status returnedfrom the cancelation requests. */printf("got SIGQUIT; canceling I/O requests: \n");for (size_t j = 0; j < numReqs; j++) {if (ioList[j].status == EINPROGRESS) {printf("    Request %zu on descriptor %d:", j,ioList[j].aiocbp->aio_fildes);s = aio_cancel(ioList[j].aiocbp->aio_fildes,ioList[j].aiocbp);if (s == AIO_CANCELED)printf("I/O canceled\n");else if (s == AIO_NOTCANCELED)printf("I/O not canceled\n");else if (s == AIO_ALLDONE)printf("I/O all done\n");elseperror("aio_cancel");}}gotSIGQUIT = 0;}/* Check the status of each I/O request that is stillin progress. */printf("aio_error():\n");for (size_t j = 0; j < numReqs; j++) {if (ioList[j].status == EINPROGRESS) {printf("    for request %zu (descriptor %d): ",j, ioList[j].aiocbp->aio_fildes);ioList[j].status = aio_error(ioList[j].aiocbp);switch (ioList[j].status) {case 0:printf("I/O succeeded\n");break;case EINPROGRESS:printf("In progress\n");break;case ECANCELED:printf("Canceled\n");break;default:perror("aio_error");break;}if (ioList[j].status != EINPROGRESS)openReqs--;}}}printf("All I/O requests completed\n");/* Check status return of all I/O requests. */printf("aio_return():\n");for (size_t j = 0; j < numReqs; j++) {ssize_t s;s = aio_return(ioList[j].aiocbp);printf("    for request %zu (descriptor %d): %zd\n",j, ioList[j].aiocbp->aio_fildes, s);}exit(EXIT_SUCCESS);}

参考

wiyi
linux-aio

http://www.dtcms.com/a/351059.html

相关文章:

  • 绿算技术解密金融科技安全:高性能计算与存储驱动金融防火墙新时代
  • 系统安全难题咋解?低代码给出新思路
  • 打破技术壁垒的先进制造框架的智慧工业开源了
  • 医疗巡诊车5G专网路由器应用
  • 360智脑开源优化排序模型——360Zhinao-1.8B-Reranking本地部署教程,提升检索质量,减少大模型“幻觉”现象
  • Windows编程日志4——消息队列和消息处理
  • Hive的核心架构
  • Go语言模块开发
  • 从线到机:AI 与多模态交互如何重塑 B 端与 App 界面设计
  • S-HUB实现泛微E9与飞书对接
  • Redisson详解:高性能redis客户端,超详细!
  • MyBatis 初识:框架定位与核心原理——SQL 自由掌控的艺术
  • 【资讯】国内免费/开源大模型对比及获得途径总结
  • 书生大模型InternLM2:从2.6T数据到200K上下文的开源模型王者
  • 实体店转型破局之道:新零售社区商城小程序开发重构经营生态
  • kafka消费顺序保障
  • Kafa面试经典题--Kafka为什么吞吐量大,速度快
  • 高校科技成果转化生态价值重构
  • Go函数详解:从基础到高阶应用
  • Ubuntu Server 快速部署长安链:基于 Go 的智能合约实现商品溯源
  • 质押、ETF、财库三箭齐发:以太坊价值逻辑的重构与演进
  • Linux系统中,利用sed命令删除文档空格的方法汇总
  • Redis ZSET 深度剖析:从命令、原理到实战
  • 基于 Elasticsearch 解决分库分表查询难题
  • [Maven 基础课程]Maven 是什么
  • 【Linux操作系统】简学深悟启示录:环境变量进程地址
  • Java基础第5天总结(final关键字,枚举,抽象类)
  • Redis-数据类型与常用命令
  • Java数据结构——9.排序
  • 【OpenAI】ChatGPT-4o 全能AI-omni的详细介绍+API KET的使用教程!