ZLMediaKit中的线程

EventLoop的线程模型

服务器通用的IO模型event-loop + 非阻塞IO。线程模型可以是单线程,可以是多线程。对于已经普及了的多核环境,通常都是采用多线程。

通常一个线程中有一个EventLoop,比如accept是一个专门线程,accept后的fd分到不同线程中,一个fd只会在一个EventLoop中处理。那么也可以说是一个EventLoop就代表了一个线程。在ZLMediaKit中线程就是这种抽象。

EventLoop的基本实现就是IO多路复用(select,epoll等)+消息队列,它不止可以用于处理IO。也可以当作消息队列或定时器使用。

这种方式非常适用于对线程职责的划分,将特定的业务通过消息队列分到固定的线程。在webrtc中,rtc::thread也是种实现。它同时作为网络线程,信令线程,工作线程使用。其中工作线程并没有IO功能。 详细见webrtc中的rtc::thread

ZLMediaKit中的EventLoop

线程

EventLoop在众多的开源网络库都有实现。ZLMediaKit的实现非常适合用于多线程模型。

企业微信截图_17014217474387.png

以上为其类图,EventPoller就是EventLoop,为一个事件循环。它继承自TaskExecutor,代表了一个线程。

其中的方法asyncsync分别代表着向线程投递异步任务同步任务(在TaskExecutorInterface中定义)。它还包括了计算CPU负载的功能(在ThreadLoadCounter中定义)。

所以EventPoller是一个功能相当完备的线程:

  • 有事件循环
  • 可以向其投递任务。
  • 可以计算CPU负载,结合线程池一起使用,选取负载低的线程。

线程池

企业微信截图_1701421705841.png

以上为ZLMediaKit中线程池类图,通过EventPollerPoollgetPollergetFirstPoller方法来取一个线程(EventPoller)。getPoller优先取一个CPU负载小的线程。

使用

产生一个线程

在ZLMediaKit中通过EventPollerPool来获取一个EventPoller,如下代码:

EventPollerPool::setPoolSize(thread_num);
auto poller = EventPollerPool::Instance().getPoller();

EventPollerPool::setPoolSize(thread_num)设置线程数,当产生线程池对象EventPollerPool时,线程都已创建并绑定到了核上,通过getPoller()方法获取一个CPU负责最小的线程。上面的poller对象就代表了一个线程。

向线程投递一个任务

通过async,比如如下代码:

poller->async([invoker,contentOut](){
                HttpSession::KeyValue headerOut;
                //你可以自定义header,如果跟默认header重名,则会覆盖之
                //默认header有:Server,Connection,Date,Content-Type,Content-Length
                //请勿覆盖Connection、Content-Length键
                //键名覆盖时不区分大小写
                headerOut["TestHeader"] = "HeaderValue";
                invoker(200,headerOut,contentOut);
            });

通过doDelayTask向线程投递定时任务,如下代码:

poller->doDelayTask((uint64_t) (second * 1000), [cb, second]() {
        try {
            if (cb()) {
                //重复的任务
                return (uint64_t) (1000 * second);
            }
            //该任务不再重复
            return (uint64_t) 0;
        } catch (std::exception &ex) {
            ErrorL << "Exception occurred when do timer task: " << ex.what();
            return (uint64_t) (1000 * second);
        }
    });

瑕疵

  • EventPoller的构造函数都被设置为了私有,只能通过EventPollerPool::Instance().getPoller()获取,这有些不方便。在一些场景,程序会被划分成了固定的线程,而不需要使用线程池。
  • 如果能提供将当前线程保证成EventPoller线程的功能就更好了。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

mo4776

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

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

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

打赏作者

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

抵扣说明:

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

余额充值