鸿蒙源码阅读-- 用户程序框架中的libevent 原创 精华

拓维信息流沙客
发布于 2023-2-11 23:14
浏览
0收藏

概念简述

用户程序框架存在一种异步操作相关的框架,对于应用程序,需要保证ui线程不被阻塞,这个框架便保证了这样的一个机制。

eventhandler:

是一种用户在当前线程上投递InnerEvent事件或者Runnable任务到异步线程上处理的机制;

eventRunner

是存在一个线程上的事件循环器

eventQuene

存在于eventRunner中管理innerEvent的数据结构

innerEvent

用于投递的事件(也包括任务,线程间通信以及异步任务处理)

源码相关分析

innerEvent

class InnerEvent final {
public:
    using Clock = std::chrono::steady_clock;
    using TimePoint = std::chrono::time_point<Clock>;
    using Callback = std::function<void()>;
    using Pointer = std::unique_ptr<InnerEvent, void (*)(InnerEvent *)>;

    class Waiter {
    public:
        Waiter() = default;
        virtual ~Waiter() = default;
        DISALLOW_COPY_AND_MOVE(Waiter);

        virtual void Wait() = 0;
        virtual void Notify() = 0;
    };

    DISALLOW_COPY_AND_MOVE(InnerEvent);

    /**
     * Get InnerEvent instance from pool.
     *
     * @param innerEventId The id of the event.
     * @param param Basic parameter of the event, default is 0.
     * @return Returns the pointer of InnerEvent instance.
     */
    static Pointer Get(uint32_t innerEventId, int64_t param = 0);

    /**
     * Get InnerEvent instance from pool.
     *
     * @param innerEventId The id of the event.
     * @param object Shared pointer of the object.
     * @param param Basic parameter of the event, default is 0.
     * @return Returns the pointer of InnerEvent instance.
     */
    template <typename T>
    static inline Pointer Get(uint32_t innerEventId, const std::shared_ptr<T> &object, int64_t param = 0)
    {
        auto event = Get(innerEventId, param);
        event->SaveSharedPtr(object);
        return event;
    }
    ......

所有的innerEvent 存在一个eventPool管理,Get方法是获取事件的结构,重载了很多的不同参数。

返回为innerEvent一个unique_ptr,这种独占式指针,但注意模板参数的析构方法不是默认的,其实重载的deleter就是eventPool去回收这些已经被消耗掉的事件了。

        // Allocate new memory, while pool is empty.
        return InnerEvent::Pointer(new InnerEvent, Drop);
    }

private:
    static void Drop(InnerEvent *event)
    {
        if (event == nullptr) {
            return;
        }

        auto destructor = [](InnerEvent *event) {
            if (event != nullptr) {
                delete event;
            }
        };

        // Clear content of the event
        event->ClearEvent();
        // Put event into event buffer pool
        GetInstance().Put(InnerEvent::Pointer(event, destructor));
    }

可以看到事件被消耗后又放回了event buffer pool

innerevent针对用户开发可以分为两种一个发送线程消息,另一个是投递任务。一般来说发送消息,需要用户去处理事件,这个用在eventHandler中的ProcessEvent处理,所以不同的handler需要自己实现ProcessEvent方法。

void EventHandler::DistributeEvent(const InnerEvent::Pointer &event)
{
    if (!event) {
        HILOGE("DistributeEvent: Could not distribute an invalid event");
        return;
    }

    // Save old event handler.
    std::weak_ptr<EventHandler> oldHandler = currentEventHandler;
    // Save current event handler into thread local data.
    currentEventHandler = shared_from_this();
    if (event->HasTask()) {
        // Call task callback directly if contains a task.
        (event->GetTaskCallback())();
    } else {
        // Otherwise let developers to handle it.
        ProcessEvent(event);
    }

可以看到EventHandler::DistributeEvent会做相关处理。

void Run() final
    {
        // Prepare to start event loop.
        queue_->Prepare();

        // Make sure instance of 'EventRunner' exists.
        if (owner_.expired()) {
            return;
        }

        threadId_ = std::this_thread::get_id();

        // Save old event runner.
        std::weak_ptr<EventRunner> oldRunner = currentEventRunner;
        // Set current event runner into thread local data.
        currentEventRunner = owner_;

        // Start event looper.
        for (auto event = queue_->GetEvent(); event; event = queue_->GetEvent()) {
            std::shared_ptr<EventHandler> handler = event->GetOwner();
            // Make sure owner of the event exists.
            if (handler) {
                std::shared_ptr<Logger> logging = logger_;
                std::stringstream address;
                address << handler.get();
                if (logging != nullptr) {
                    if (!event->HasTask()) {
                        logging->Log("Dispatching to handler event id = " + std::to_string(event->GetInnerEventId()));
                    } else {
                        logging->Log("Dispatching to handler event task name = " + event->GetTaskName());
                    }
                }

                handler->DistributeEvent(event);

                if (logging != nullptr) {
                    logging->Log("Finished to handler(0x" + address.str() + ")");
                }
            }

DistributeEvent 方法会在 eventRuner中的loop中被调用。

再看看eventQuene的相关实现

    std::mutex queueLock_;

    // Sub event queues for different priority.
    std::array<SubEventQueue, SUB_EVENT_QUEUE_NUM> subEventQueues_;

    // Event queue for IDLE events.
    std::list<InnerEvent::Pointer> idleEvents_;

    // Next wake up time when block in 'GetEvent'.
    InnerEvent::TimePoint wakeUpTime_{InnerEvent::TimePoint::max()};

    // Mark if in idle mode, and record the start time of idle.
    InnerEvent::TimePoint idleTimeStamp_{InnerEvent::Clock::now()};

    bool isIdle_{true};

    // Mark if the event queue is finished.
    bool finished_{true};

    // IO waiter used to block if no events while calling 'GetEvent'.
    std::shared_ptr<IoWaiter> ioWaiter_;

    // File descriptor listeners to handle IO events.
    std::map<int32_t, std::shared_ptr<FileDescriptorListener>> listeners_;

它的成员变量,包括了互斥锁,状态机管理,不同的队列

感觉说明几个类的关系,画一个类图会更加直观一点,后续有时间更新。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
3
收藏
回复
举报
1条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

分析部分学习了

回复
2023-2-13 09:55:32
回复
    相关推荐