/* * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved. * * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit). * * Use of this source code is governed by MIT license that can be found in the * LICENSE file in the root of the source tree. All contributing project authors * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_UTIL_NOTICECENTER_H_ #define SRC_UTIL_NOTICECENTER_H_ #include #include #include #include #include #include #include #include "util.h" #include "function_traits.h" namespace toolkit { class EventDispatcher { public: friend class NoticeCenter; using Ptr = std::shared_ptr; ~EventDispatcher() = default; private: using MapType = std::unordered_multimap; EventDispatcher() = default; class InterruptException : public std::runtime_error { public: InterruptException() : std::runtime_error("InterruptException") {} ~InterruptException() {} }; template int emitEvent(bool safe, ArgsType &&...args) { using stl_func = std::function(args))...)>; decltype(_mapListener) copy; { // 先拷贝(开销比较小),目的是防止在触发回调时还是上锁状态从而导致交叉互锁 std::lock_guard lck(_mtxListener); copy = _mapListener; } int ret = 0; for (auto &pr : copy) { try { pr.second.get(safe)(std::forward(args)...); ++ret; } catch (InterruptException &) { ++ret; break; } } return ret; } template void addListener(void *tag, FUNC &&func) { using stl_func = typename function_traits::type>::stl_function_type; Any listener; listener.set(std::forward(func)); std::lock_guard lck(_mtxListener); _mapListener.emplace(tag, listener); } void delListener(void *tag, bool &empty) { std::lock_guard lck(_mtxListener); _mapListener.erase(tag); empty = _mapListener.empty(); } private: std::recursive_mutex _mtxListener; MapType _mapListener; }; class NoticeCenter : public std::enable_shared_from_this { public: using Ptr = std::shared_ptr; static NoticeCenter &Instance(); template int emitEvent(const std::string &event, ArgsType &&...args) { return emitEvent_l(false, event, std::forward(args)...); } template int emitEventSafe(const std::string &event, ArgsType &&...args) { return emitEvent_l(true, event, std::forward(args)...); } template void addListener(void *tag, const std::string &event, FUNC &&func) { getDispatcher(event, true)->addListener(tag, std::forward(func)); } void delListener(void *tag, const std::string &event) { auto dispatcher = getDispatcher(event); if (!dispatcher) { // 不存在该事件 return; } bool empty; dispatcher->delListener(tag, empty); if (empty) { delDispatcher(event, dispatcher); } } // 这个方法性能比较差 void delListener(void *tag) { std::lock_guard lck(_mtxListener); bool empty; for (auto it = _mapListener.begin(); it != _mapListener.end();) { it->second->delListener(tag, empty); if (empty) { it = _mapListener.erase(it); continue; } ++it; } } void clearAll() { std::lock_guard lck(_mtxListener); _mapListener.clear(); } private: template int emitEvent_l(bool safe, const std::string &event, ArgsType &&...args) { auto dispatcher = getDispatcher(event); if (!dispatcher) { // 该事件无人监听 return 0; } return dispatcher->emitEvent(safe, std::forward(args)...); } EventDispatcher::Ptr getDispatcher(const std::string &event, bool create = false) { std::lock_guard lck(_mtxListener); auto it = _mapListener.find(event); if (it != _mapListener.end()) { return it->second; } if (create) { // 如果为空则创建一个 EventDispatcher::Ptr dispatcher(new EventDispatcher()); _mapListener.emplace(event, dispatcher); return dispatcher; } return nullptr; } void delDispatcher(const std::string &event, const EventDispatcher::Ptr &dispatcher) { std::lock_guard lck(_mtxListener); auto it = _mapListener.find(event); if (it != _mapListener.end() && dispatcher == it->second) { // 两者相同则删除 _mapListener.erase(it); } } private: std::recursive_mutex _mtxListener; std::unordered_map _mapListener; }; template struct NoticeHelper; template struct NoticeHelper { public: template static int emit(const std::string &event, ArgsType &&...args) { return emit(NoticeCenter::Instance(), event, std::forward(args)...); } template static int emit(NoticeCenter ¢er, const std::string &event, ArgsType &&...args) { return center.emitEventSafe(event, std::forward(args)...); } }; #define NOTICE_EMIT(types, ...) NoticeHelper::emit(__VA_ARGS__) } /* namespace toolkit */ #endif /* SRC_UTIL_NOTICECENTER_H_ */