uloop分析和非阻塞标准输入的一种应用

什么是uloop

uloop是libubox的一个模块,而libubox是openwrt的一个基础库。本文对libubox不重点敞开讨论。重点记录下自己项目中使用uloop的应用。

uloop重点有三个功能:文件描述符触发事件的监控,timeout定时器处理, 当前进程的子进程的维护。其实是一种最简化的伪线程机制,可以将事务、定时器通过触发文件描述符fd的监控。

对于linux应用开发,涉及一些小业务场景(数据转发量不大的业务控制类),又需要监听不同fd的场景,如需要创建多个socket通信,大家一般就thread开起来。

多线程的好处就不多描述,大家baid一堆。但也带来了缺陷,如线程之间做需要互斥。然后在简单的业务控制场景,对并行要求并不高的,用一个单线程即能解决的事情,就不要用多线程去搞,除了编码带来的复杂性,也带来了不安全性和系统资源浪费。

伪线程

不同业务的事务触发条件、时机不一样,处理方法也不一样,一个单线程如何解决。

伪线程的概念即通过单线程来模拟多任务,做过RTOS的都知道,由MCU触发硬件中断,注册中断处理函数,来实现不同中断(业务)的处理。uloop采用类似的结构,只是通过文件描述符来解决。

    ufd.fd = socket(...);    
    ufd.cb = socket_recv_cb;
    uloop_fd_add(&ufd, ULOOP_READ);

 如上,一个uloop简单的事务处理注册方法,监听某个socket,当有数据时候,回调到ufd.cb函数进行处理。

uloop架构

前面说到的uloop的三大功能,在uloop模块内维护着三个全局变量poll_fd,timeouts-链表,processes-链表

主要框架:

  • 初始化事件循环

  int uloop_init(void)

  创建一个epoll的句柄,最多监控32个文件描述符。

  设置文件描述符属性,如FD_CLOEXEC。

  • 事件循环主处理入口

  void uloop_run(void)

  • 销毁事件循环

  void uloop_done(void)

  关闭epoll句柄。

  清空定时器链表中的所有的定时器。

  清空进程处理事件链表中删除所有的进程事件节点。

重点看uloop_run():

while(!uloop_cancelled)
    {
        uloop_gettime(&tv);
        uloop_process_timeouts(&tv);
        if (uloop_cancelled)
            break;

        if (do_sigchld)
            uloop_handle_processes();
        uloop_run_events(uloop_get_next_timeout(&tv));
    }

  1.  查看定时器链表第一个节点是否到期,到期则执行该节点的处理函数(定时器节点按时间顺序排序加入到链表)
  2. 处理子进程事务。(本节暂不讨论)
  3. 判断所有fd是否已触发了事务-由epoll机制方式,如已产生事件则触发该fd的处理函数。可注册的事务包括:

#define ULOOP_READ        (1 << 0)
#define ULOOP_WRITE        (1 << 1)
#define ULOOP_EDGE_TRIGGER    (1 << 2)
#define ULOOP_BLOCKING        (1 << 3)

#define ULOOP_EVENT_MASK    (ULOOP_READ | ULOOP_WRITE)

 应用

我们常用的控制台输入方法,scanf或getchar,这两个方法是阻塞的,会一直等待控制台输入返回后才会继续往下执行,如果一个场景需要等待同时,又能处理其他事情,即可用到uloop方式:

本例,通过uloop创建了一个定时器,每2s打印一下,同时又监听控制台输入,如果有输入,则重复打印一次输入内容:

/*recv message */
static void input_recv_cb(struct uloop_fd *fd, unsigned int events)
{
    uint16_t data_len = 0;

    memset(g_read_buf, 0, FRAME_MAX_LEN);
    data_len = input_read(g_read_buf, fd->fd);
    nlog("input:%s\n", (char *)g_read_buf);
    return;
}

static void print_cb(struct uloop_timeout *t)
{
    printf("print here\n");
    uloop_timeout_set(&printf_timeout, 2*1000);
}

static void nt_init()
{
    ufd.fd = 0;//标准输入
    
    ufd.cb = input_recv_cb;
    uloop_fd_add(&ufd, ULOOP_READ);

    printf_timeout.cb = print_cb;
    uloop_timeout_set(&printf_timeout, 2*1000);//2s打印一次
}

int main(void)
{
    uloop_init();

    nt_init();

    uloop_run();
    uloop_done();

    return 0;
}
 

 详细的代码:(内含uloop模块)

https://download.csdn.net/download/zcqiang2012/12392927

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zcqiang_zh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值