• epoll使用实例


    Android的Looper机制中,MessageQueue阻塞的方式是通过Linux的epoll机制,IO多路复用机制,这里不说原理,说一下epoll使用机制,还是参数的解析。

    实例代码

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define TAG "NATIVE-LIB"
    #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG,  __VA_ARGS__)
    
    #define POLL_WAITING_TIME -1
    #define POLL_MAX_SIZE 1
    #define POLL_WAIT_MAX_SIZE 10
    
    int error;
    int fd[2];
    int epoll_fd = 0;
    int running = 0;
    
    static void* native_thread(void* args) {
        LOGI("启动线程 -------------------- ");
        error = pipe(fd);
        LOGI("pipe结果 : -------------------- %d", error);
        epoll_fd = epoll_create(POLL_MAX_SIZE);
        struct epoll_event ev, events[POLL_WAIT_MAX_SIZE];
        ev.events = EPOLLIN;
        ev.data.fd = fd[0];
        error = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd[0], &ev);
        LOGI("epoll_ctl结果 : -------------------- %d", error);
        running = 1;
        while (running) {
            LOGI("等待输入数据 -------------------- ");
            int count = epoll_wait(epoll_fd, events, POLL_WAIT_MAX_SIZE, POLL_WAITING_TIME);
            if (count == 0) {
                LOGI("等待超时 -------------------- ");
            } else {
                LOGI("发现输入数据 -------------------- %d", count);
                int data[1];
                for (int i = 0; i < count; i++) {
                    if (events[i].data.fd == fd[0] && events[i].events & EPOLLIN) {
                        read(events[i].data.fd, data, sizeof(data));
                        LOGI("输入数据值 : -------------------- %d", data[0]);
                    }
                }
            }
        }
        running = false;
        close(fd[0]);
        close(fd[1]);
        LOGI("停止线程 -------------------- ");
    }
    
    extern "C"
    JNIEXPORT void JNICALL
    Java_com_johan_epoll_EPollNative_00024Companion_start(JNIEnv *env, jobject thiz) {
        if (running == 1) {
            return;
        }
        pthread_t id;
        pthread_create(&id, NULL, native_thread, NULL);
    }
    
    extern "C"
    JNIEXPORT void JNICALL
    Java_com_johan_epoll_EPollNative_00024Companion_stop(JNIEnv *env, jobject thiz) {
        running = 0;
    }
    
    extern "C"
    JNIEXPORT void JNICALL
    Java_com_johan_epoll_EPollNative_00024Companion_notify(JNIEnv *env, jobject thiz, jint number) {
        int data[1];
        data[0] = number;
        if (running) {
            error = write(fd[1], data, sizeof(data));
            LOGI("写入数据值 : -------------------- %d, %d, %d, %d", fd, data[0], sizeof(data), error);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    epoll相关函数解析

    // 头文件
    #include 
    
    • 1
    • 2

    如果要使用epoll机制,头文件必须引用

    // 表示创建一个epoll句柄
    int epoll_create(int _size)
    
    • 1
    • 2
    // 对上述创建的epoll句柄进行操作
    int epoll_ctl(int __epoll_fd, int __op, int __fd, struct epoll_event* __event);
    
    • 1
    • 2
    • __epoll_fd :epoll句柄,也就是epoll_create返回的值
    • __op :本次的操作
      EPOLL_CTL_ADD:向epoll句柄注册一个fd
      EPOLL_CTL_MOD:向epoll句柄修改一个已经注册的fd
      EPOLL_CTL_DEL:删除一个已经注册在epoll句柄中的fd
    • __fd :被监听的文件描述符
    • __event :事件结构体
    struct epoll_event {
    	uint32_t events;
    	epoll_data_t data;
    }
    
    • 1
    • 2
    • 3
    • 4
    • events :被监听的事件
      EPOLLIN:表示被监听的fd有可以读的数据
      EPOLLOUT:表示被监听的fd有可以写的数据
      EPOLLPRI:表示有可读的紧急数据
      EPOLLERR:对应的fd发生异常
      EPOLLHUP:对应的fd被挂断
      EPOLLET:设置EPOLL为边缘触发
      EPOLLONESHOT:只监听一次
    • data :我们只需要设置data.fd就行了,data.fd参数值就是上面的fd参数值
    // 等待处于epoll上被监听的fd产生对应的事件
    int epoll_wait(int __epoll_fd, struct epoll_event* __events, int __event_count, int __timeout_ms);
    
    • 1
    • 2
    • __epoll_fd :epoll句柄,也就是epoll_create返回的值
    • __events :事件数组,触发事件时,会保存到这个数组供我们使用,只要声明就行了,是一个数组
    • __event_count :最大响应事件数量
    • __timeout_ms :最大等待时长,单位ms,如果不要超时,设置为0

    pipe相关参数解析

    pipe为管道,调用pipe系统函数即可创建一个管道。有如下特质:

    1. 其本质是一个伪文件(实为内核缓冲区)

    2. 由两个文件描述符引用,一个表示读端,一个表示写端。

    3. 规定数据从管道的写端流入管道,从读端流出。

    管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。

    实例这里有使用到,稍微说一下,需要知道的是,创建是一读一写,所以会声明2个fd,也就是fd[2],想知道更详细需要查阅相关文档;

    参考

    Android 消息处理以及epoll机制
    浅谈Android之Linux pipe/epoll

  • 相关阅读:
    Linux启动流程描述
    【DETR】End-to-End Object Detection with Transformers
    【Linux】虚拟机安装Linux、客户端工具,MobaXterm的使用,Linux常用命令
    【Rust指南】use关键字妙用|模块内容拆分
    工业自动化与物联网技术的融合:开启智能制造新时代
    第7-9 章项目成熟度模型
    Word控件Aspose.Words for .NET.更新至最新v22.6,更多功能增强及漏洞修复
    从零开始Blazor Server(4)--登录系统
    深度学习(part8)--CNN卷积神经网络
    首个零售金融大模型落地,驱动金融业数字化进阶
  • 原文地址:https://blog.csdn.net/JohanMan/article/details/126386778