抽象异步Call设计实例,用于处理异步回调和任务调度

业务痛点

        历史包袱——使用原生mars组件进行小包的收发,弱网场景下单实例的mars不能支撑高频&多样的业务模型,所以迫切需要一个支持多实例的网络组件来处理业务收发,libevent是一个方案。由于libevent本身并没有封装任务调度器,需要自行设计开发。

设计思路

        设计一个异步事件发生器,借助libevent支持延迟触发,借助socket实现进程间通信,这样能很好地支持业务中所有需要同步接口改异步的需求。 很简单,内部开个线程处理回调队列,增加延迟触发逻辑。

代码实现    

namespace MsgComm {
    class ClientEventLoopConcrete : public ClientEventLoop {
    public:
        ClientEventLoopConcrete();
        ~ClientEventLoopConcrete() override;

        struct event_base* EventBase() override {
            return m_eventBase;
        }

        int AsyncCall(std::weak_ptr<ClientEventLoopCallback> callBack, const uint64_t& delay) override;
    private:
        friend std::shared_ptr<ClientEventLoop> GetEventLoop(const ClientEventLoopType& type);
        friend void OnClientEventLoopConcreteEventCallback(evutil_socket_t sockFd, short event, void *userCtx);

        int start();
        int stop();
        void threadFunc();
        void onEventCallback(evutil_socket_t sockFd, short event);
        int createSocketPair();
        void destroySocketPair();
        void onAlarm();

        struct event_base*                                                      m_eventBase;
        struct event*                                                           m_event;
        std::atomic_bool                                                        m_exitFlag;
        std::thread                                                             m_thread;
        std::mutex                                                              m_mutex;
        std::condition_variable                                                 m_condition;
        std::map<int64_t, std::list<std::weak_ptr<ClientEventLoopCallback>>>    m_callBacks;
        evutil_socket_t                                                         m_socketPair[2];
        std::shared_ptr<Alarm>                                                  m_alarm;
#ifdef ANDROID
        std::shared_ptr<WakeUpLock>                                             m_wakeupLock;
#endif
    };
};

namespace MsgComm {

#define DEFAULT_SLEEP_TIME_SEC  (10)
#define DEFAULT_SLEEP_TIME_USEC (0)

    void OnClientEventLoopConcreteEventCallback(evutil_socket_t sockFd, short event, void *userCtx) {
        if (userCtx != nullptr) {
            reinterpret_cast<ClientEventLoopConcrete*>(userCtx)->onEventCallback(sockFd, event);
        }
    }

    ClientEventLoopConcrete::ClientEventLoopConcrete() : m_eventBase(nullptr),
                                                         m_event(nullptr),
                                                         m_exitFlag(true),
                                                         m_socketPair{-1} {
#ifdef ANDROID
        m_wakeupLock = std::make_shared<WakeUpLock>();
#endif
        m_alarm = std::make_shared<Alarm>([this] () {
            onAlarm();
        }, true);
        xwarn2(TSF"create ClientEventLoopConcrete!");
    }

    ClientEventLoopConcrete::~ClientEventLoopConcrete() {
        m_alarm.reset();
#ifdef ANDROID
        m_wakeupLock.reset();
#endif
        xwarn2(TSF"destroy ClientEventLoopConcrete!");
        stop();
        xwarn2(TSF"destroy ClientEventLoopConcrete!");
    }

    int ClientEventLoopConcrete::AsyncCall(std::weak_ptr<ClientEventLoopCallback> callBack, const uint64_t &delay) {
        std::lock_guard<std::mutex> _l(m_mutex);
        if (m_exitFlag) {
            xerror2(TSF"m_exitFlag is true!");
            return -1;
        }

        auto ts = timeMs() + delay;
        bool needSend = true;

        if (!m_callBacks.empty()) {
            if (m_callBacks.begin()->first < delay) {
                needSend = false;
            }
        }
        m_callBacks[ts].emplace_back(callBack);
        if (needSend && (m_socketPair[0] > 0)) {
            send(m_socketPair[0], "1", 1, 0);
        }
        return 0;
    }

    int ClientEventLoopConcrete::createSocketPair() {
        destroySocketPair();

#ifdef WIN32
        auto ret = evutil_socketpair(AF_INET, SOCK_STREAM, 0, m_socketPair);
#else
        auto ret = evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, m_socketPair);
#endif
        if (ret <
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ปรัชญา แค้วคำมูล

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

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

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

打赏作者

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

抵扣说明:

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

余额充值