epoll使用实例

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

实例代码

#include <jni.h>
#include <string>
#include <pthread.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <android/log.h>

#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);
    }
}

epoll相关函数解析

// 头文件
#include <sys/epoll>

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

// 表示创建一个epoll句柄
int epoll_create(int _size)
// 对上述创建的epoll句柄进行操作
int epoll_ctl(int __epoll_fd, int __op, int __fd, struct epoll_event* __event);
  • __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;
}
  • 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);
  • __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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值