ZLMediaKit 服务器源码解读---广播、通知中心(NoticeCenter)

源码实在是简单,在这就简单描述2个过程

一:事件监听

当需要监听事件时,调用NoticeCenter的addListener函数,调用者将事件类型(event),标识(tag),处理函数(func),addListener函数根据事件类型先找到事件派发器(没有则会创建),然后调用其addListener函数

  template<typename FUNC>
    void addListener(void *tag, const string &event, FUNC &&func) {
    
    
        getDispatcher(event, true)->addListener(tag, std::forward<FUNC>(func));
    }

EventDispatcher的addListener函数如下,该函数将标识(tag),处理函数(func)插入自身的成员变量_mapListener,这是一个键值对。存储了多个执行函数

    template<typename FUNC>
    void addListener(void *tag, FUNC &&func) {
    
    
        typedef typename function_traits<typename std::remove_reference<FUNC>::type>::stl_function_type funType;
        std::shared_ptr<void> pListener(new funType(std::forward<FUNC>(func)), [](void *ptr) {
    
    
            funType *obj = (funType *) ptr;
            delete obj;
        });
        lock_guard<recursive_mutex> lck(_mtxListener);
        _mapListener.emplace(tag, pListener);
    }

所以当添加事件监听时,就会将需要监听的事件与该事件的处理函数全部保存

二:事件触发

调用函数如下,也是先找到事件派发器,然后执行他emitEvent函数

template<typename ...ArgsType>
    int emitEvent(const string &strEvent, ArgsType &&...args) {
    
    
        auto dispatcher = getDispatcher(strEvent);
        if (!dispatcher) {
    
    
            //该事件无人监听
            return 0;
        }
        return dispatcher->emitEvent(std::forward<ArgsType>(args)...);
    }

EventDispatcher的emitEvent函数如下,很容易理解,就是遍历_mapListener,然后执行里面保存的处理函数,也就是添加事件监听时传递进来的处理函数,

template<typename ...ArgsType>
    int emitEvent(ArgsType &&...args) {
    
    
        typedef function<void(decltype(std::forward<ArgsType>(args))...)> funType;
        decltype(_mapListener) copy;
        {
    
    
            //先拷贝(开销比较小),目的是防止在触发回调时还是上锁状态从而导致交叉互锁
            lock_guard<recursive_mutex> lck(_mtxListener);
            copy = _mapListener;
        }

        int ret = 0;
        for (auto &pr : copy) {
    
    
            funType *obj = (funType *) (pr.second.get());
            try {
    
    
                (*obj)(std::forward<ArgsType>(args)...);
                ++ret;
            } catch (InterruptException &) {
    
    
                ++ret;
                break;
            }
        }
        return ret;
    }

三:总结

逻辑就很简单,
1、调用者需要监听某一个事件时,由通知中心(NoticeCenter)找到事件派发器(EventDispatcher),同时将事件类型和事件处理函数传递进去,然后由事件派发器(EventDispatcher)保存所有处理函数
2、当某处触发事件时(开启通知),由通知中心(NoticeCenter)找到事件派发器(EventDispatcher),然后由事件派发器(EventDispatcher)轮巡执行所有保存的处理函数,这样所有加入监听的都能执行他们想要执行的任务。
3、注意:如果处理函数没有做异步处理,那么他归属的线程在触发事件里,就是在emitEvent时的线程,而不是在调用者所在的线程,

猜你喜欢

转载自blog.csdn.net/dai1396734/article/details/123184326