首页 > 系统相关 >linux文件IO:epoll

linux文件IO:epoll

时间:2024-12-15 16:42:06浏览次数:9  
标签:epoll int events epfd fd IO linux event

poll和select的改进版,在一个程序需要处理数百个文件描述符时很有用

2.6内核引入epoll机制,解决了poll和select的性能问题,并加入了一些新特性
poll和select每次调用都需要所有被监听的文件描述符,内核需要遍历所有的文件描述符,当数量变大时,性能消耗巨大

epoll将监听注册从实际监听中分离,从而解决了该问题
一个系统调用初始化一个epoll上下文,另一个从上下文中加入和删除文件描述符,第三个执行真正的事件等待

创建一个epoll实例

#include<sys/epoll.h>
int epoll_create(int size);

创建一个epoll实例,返回与该实例相关的文件描述符
size指定需要监听的文件描述符数量,传递一个近似值会带来性能提升

出错时返回-1,并设置errno
EINVAL size不是正数
ENFILE 系统达到打开文件数上限
ENOMEN 没有足够内存完成操作

int epfd= epoll_create(100);
if(epfd<0){
  perror("epoll create err");
}

文件描述符需要调用close关闭

控制epoll

#include<sys/epoll.h>
int epoll_ctl(int epfd, in op, int fd, struct epoll_event* event);

向指定的epoll上下文加入或删除文件描述符

struct epoll_event{
  __u32 events;
  union{
    void* ptr;
    int fd;
    __u32 u32;
    __u64 u64;
  }data;
};

参数op指定要对fd进行的操作
参数event指定更具体的行为

op取值如下

op字段 说明
EPOLL_CTL_ADD 添加fd到epfd指定的epoll实例中
EPOLL_CTL_MOD 使用event修改在已有fd上的监听行为
EPOLL_CTL_DEL 从epfd指定的epoll实例中删除fd

epoll_event结构体指定了在文件描述符上的监听事件
epoll_event.events字段取值如下,可用位或运算符同时设置

events字段 说明
EPOLLERR 文件出错,即使没有设置,该事件也是会被监听
EPOLLET 在监听文件上开启边沿触发
EPOLLHUP 文件被挂起,即使没有设置,该事件也是会被监听
EPOLLIN 文件未阻塞,可读
EPOLLONESHOT 在一次事件产生并被处理后,文件不再被监听
EPOLLOUT 文件未阻塞,可写
EPOLLPRI 高优先级的带外数据可读

epoll_event.data字段由用户使用,确认事件后会返回给用户
通常将epoll_event.data.fd设置为指定的fd,从而可以知道触发事件的文件描述符

返回值,成功返回0,失败返回-1,并设置errno为下列值

errno值 说明
EBADF epfd不是有效的epoll实例,或fd不是有效的文件描述符
EEXIST op为EPOLL_CTL_ADD,但fd已与epfd关联
EINVAL epfd不是一个epoll实例,epfd与fd相同,或op无效
ENOENT op为EPOLL_CTL_MOD和EPOLL_CTL_DEL,但fd没有与epfd关联
ENOMEN 没有足够内存完成进程请求
EPERM fd不支持epoll

在epfd实例中加入一个fd指定的监听文件

struct epoll_event evt;
evt.data.fd= fd;
evt.events= EPOLLIN | EPOLLOUT;
int ret= epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &evt);
if(ret){
  perror("epoll ctl");
}

修改epfd实例中的fd上的一个监听事件

struct epoll_event evt;
evt.data.fd= fd;
evt.events= EPOLLIN;
int ret= epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &evt);
if(ret){
  perror("epoll ctl");
}

op为EPOLL_CTL_DEL时,因为没有设置事件,event参数可以为NULL

等待epoll事件

#include<sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event* event, int maxevents, int timeout);

等待epfd实例中的fd上的事件,超时timeout毫秒
成功返回,events指向包含epoll_event结构体的内存,最多可以有maxevents个事件
返回值为事件数,出错返回-1,并设置errno为如下值

errno值 说明
EBADF epfd为无效文件描述符
EFAULT 进程对events指向的内存无写权限
EINTR 系统调用在完成前被信号中断
EINVAL epfd不是有效的epoll实例,和maxevents小于0

若timeout为0,即使没有事件发生,也会立即返回,此时调用返回0
若timeout为-1,将一直等待到有事件发生

一个完整的epoll_wait示例

#define MAX_EVENTS 64
int epfd;

struct epoll_event* events;
events= malloc(sizeof(struct epoll_event)* MAX_EVENTS);
if(!events){
  perror("malloc")
  return 0;
}

int nr_events= epoll_wait(epfd, events, MAX_EVENTS, -1);
if(nr_events<0){
  perror("epoll_wait");
  free(events);
  return 0;
}

for(int i=0; i<nr_events; i++){
  printf("event=%ld on fd=%d\n", events[i].events, events[i].data.fd);
}
free(events);

边沿触发事件和水平触发事件

epoll_ctl参数event中的events设置为EPOLLET,fd上的监听为边沿触发,相反则为水平触发

如下生产者和消费者在通过unix管道通信的情况
1.生产者向管道写入1kb数据
2.消费者在管道上调用epoll_wait,等待管道出现数据,从而可读

对于水平触发的监听,步骤2对epoll_wait的调用会立即返回
对于边沿触发的监听,调用会等到步骤1发生后才会返回,即使管道已有数据可读,调用也会等到有数据写入才会返回

水平触发是默认行为,是大多数开发者期望的,也是poll和select的行为
边沿触发需要一个不同的方式来写程序,通常利用非阻塞IO,并需要仔细检查EAGAIN

标签:epoll,int,events,epfd,fd,IO,linux,event
From: https://www.cnblogs.com/sgqmax/p/18608141

相关文章

  • Linux系统基础(一):基础操作命令
    第一节Linux基础操作文章目录第一节Linux基础操作文件操作相关文件读取相关用户相关权限相关日志相关进程相关存储相关网络相关基本工具网络配置网络连接SSH文件操作相关opensslpasswd-1123openssl是一个开源加密工具包passwd指的是用于处理密码......
  • 3种在Linux命令行查看图像的方法
    在Linux中有很多GUI应用程序可以查看图像,但是这对经常使用命令行来工作的人可能会觉得很繁琐。今天要介绍的是3个实用的CLI图像查看器来在终端上查看图像,让那些使用CLI的朋友能更加高效地工作。1.FIMFIM是FbiIMproved的缩略语,意思是Fbi改进版。有些人可能还不......
  • AtCoder Beginner Contest 384 Solution
    A-aaaadaa(abc384A)题目大意给个长度为n的字符串,以及两个字母a和b,要求把字符串中不是a的字符全部都变成b。解题思路一个循环判断一下就行了。代码#include<bits/stdc++.h>usingnamespacestd;intmain(){intn;chara,b;cin>>n>>a>>b;st......
  • 如何设置Linux系统开机自动运行脚本?
    大家好,我是良许。在工作中,我们经常有个需求,那就是在系统启动之后,自动启动某个脚本或服务。在Windows下,我们有很多方法可以设置开机启动,但在Linux系统下我们需要如何操作呢?Linux下同样可以设置开机启动,但可能需要我们敲一些命令(可能也有UI界面的设置方法,但我不熟,我更多是......
  • 18.Java Lambda 表达式(Lambda 表达式练习与原理分析、@FunctionalInterface 注解)
    一、问题引入1、问题案例开启一个新的线程,指定线程要执行的任务newThread(newRunnable(){publicvoidrun(){System.out.println("HelloWorld");}}).start();2、问题分析Thread类需要一个Runnable接口作为参数,其中抽象方法run是用来指......
  • 【无标题】minio报minio API responded with message=Access denied on the resource
    确认MinIO服务状态首先,确保MinIO服务正在运行且可以访问。您可以通过直接访问MinIO的HTTP端口(默认为9000)来检查服务状态。例如,在浏览器中访问http://<MinIO服务IP>:9000或使用命令行工具如curl来进行测试。curlhttp://<MinIO服务IP>:9000/minio/health/live如果服......
  • GameMaker Studio开发:高级动作系统_GML脚本语言的高级运用
    GML脚本语言的高级运用在上一节中,我们介绍了基本的GML脚本语言及其在GameMakerStudio中的应用。本节将深入探讨GML脚本语言的高级运用,包括函数、变量、控制结构、面向对象编程和性能优化等方面。这些内容将帮助你更好地利用GML编写复杂且高效的代码,从而提升你的游戏开发能......
  • GameMaker Studio开发:高级动作系统_案例研究:高级动作系统在不同类型游戏中的应用
    案例研究:高级动作系统在不同类型游戏中的应用在上一节中,我们探讨了如何在GameMakerStudio中构建基础的动作系统。本节将通过具体案例研究,展示高级动作系统在不同类型游戏中的应用。这些案例将涵盖常见的动作游戏类型,如平台游戏、射击游戏、格斗游戏和冒险游戏,帮助你更深入......
  • GameMaker Studio开发:高级动作系统_敌人AI与行为模式设计
    敌人AI与行为模式设计在动作游戏中,敌人AI的设计和实现是游戏体验的关键因素之一。一个精心设计的敌人AI可以让玩家感到挑战,增加游戏的趣味性和可玩性。本节将详细介绍如何在GameMakerStudio中设计和实现高级敌人AI与行为模式。敌人AI的设计原则设计敌人AI时,需要考虑以下......
  • GameMaker Studio开发:高级动作系统_动作事件的高级应用:触发与响应
    动作事件的高级应用:触发与响应在上一节中,我们讨论了如何在GameMakerStudio中设置基本的动作事件。这一节,我们将深入探讨如何利用这些事件进行更高级的触发与响应机制,以实现更复杂的游戏逻辑。通过学习本节内容,您将能够:理解不同类型的事件及其触发条件。掌握如何在事件......