C++实现仿安卓线程Handler、Message、Looper的功能

在java开发中,习惯使用Handler、Message来处理同步,比如对相机的操作(open、setParamters、start、stop、clost)全部抛到同一个线程处理,防止并发操作导致异常,这样保留给外部的统一接口就是安全的,无论外部哪些线程来调用,最终到控制模块都是在同一线程处理相机操作。这里提供一个C++实现的Handler Message封装,可以实现类似安卓那样的接口;

Handler类封装:

cpp 复制代码
#ifndef _CPP_THREADHANDLER_H
#define _CPP_THREADHANDLER_H

#include <algorithm>
#include <chrono>
#include <condition_variable>
#include <functional>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <thread>
#include "Message.h"

class ThreadHandler {
   public:
    using TimePoint_t = std::chrono::steady_clock::time_point;
    using Clock_t = std::chrono::steady_clock;
    using MillisDuration_t = std::chrono::milliseconds;
    using Task = std::function<void(const Message& msg)>;

    ThreadHandler() : _stoped(false) { initLoop(); }

    ~ThreadHandler() {
        _stoped = true;
        _cond.notify_all();
        _looper.join();
    }

    void setName(const std::string n) { this->name = n; }

    bool sendEmptyMessageDelay(int what, long delay_millis) {
        if (what < 0 || delay_millis < 0)
            return false;
        Message msg(what, delay_millis);

        std::unique_lock<std::mutex> lock(_queue_lock);
        _msg_list.push_back(msg);
        _msg_list.sort(std::less<Message>());
        _cond.notify_all();
        return true;
    }

    bool sendEmptyMessageDelay(int what) {
        return sendEmptyMessageDelay(what, 0);
    }

    bool postDelay(std::function<void()>&& f, long delay_millis) {
        if (f == nullptr || delay_millis < 0) {
            return false;
        }
        std::unique_lock<std::mutex> lock(_queue_lock);
        Message msg(0, delay_millis);
        msg.onRun(std::move(f));
        _msg_list.push_back(msg);
        _msg_list.sort(std::less<Message>());
        _cond.notify_all();
        return true;
    }

    bool post(std::function<void()>&& f) { return postDelay(std::move(f), 0); }

    void removeMessages(int what) {
        if (what < 0)
            return;

        std::unique_lock<std::mutex> lock(_queue_lock);
        if (!_msg_list.empty())
            _msg_list.remove_if(
                [what](const Message& m) { return m.what == what; });
    }

    void removeAlls() {
        std::unique_lock<std::mutex> lock(_queue_lock);
        if (!_msg_list.empty())
            _msg_list.clear();

        printf("ThreadHandler::removeAlls name: %s",
                                 name.c_str());
    }

    void stop() {
        _stoped = true;
        _cond.notify_all();
        printf("ThreadHandler::stop name: %s", name.c_str());
    }

    void handleMessage(Task&& cb) { _callback = cb; }

   private:
    void dispatchMessage(const Message& msg) const {
        if (msg.task != nullptr) {
            msg.task();
        } else {
            if (msg.what < 0 || _callback == nullptr)
                return;
            _callback(msg);
        }
    }

    void initLoop() {
        _looper = std::thread([this]() {
            while (true) {
                Message msg;
                bool isFired = false;
                {
                    std::unique_lock<std::mutex> lock(_queue_lock);
                    if (_msg_list.empty()) {
                        _cond.wait(lock, [this] {
                            return _stoped || !_msg_list.empty();
                        });
                    } else {
                        auto front = _msg_list.front();
                        // 如果要when 大于 当前时间,则休眠;否则继续往下执行
                        if (front.when > Clock_t::now()) {
                            if (front.when > Clock_t::now() + maxSleepTime) {
                                printf(
                                    "ThreadHandler::initLoop time too long name: %s, when: "
                                    "%s ,now: %s , maxSleepTime: %s",
                                    name.c_str(),
                                    std::to_string(
                                        std::chrono::duration_cast<
                                            std::chrono::seconds>(
                                            front.when.time_since_epoch())
                                            .count())
                                        .c_str(),
                                    std::to_string(
                                        std::chrono::duration_cast<
                                            std::chrono::seconds>(
                                            Clock_t::now().time_since_epoch())
                                            .count())
                                        .c_str(),
                                    std::to_string(
                                        std::chrono::duration_cast<
                                            std::chrono::seconds>(maxSleepTime)
                                            .count())
                                        .c_str());
                            }

                            _cond.wait_until(lock, front.when, [this] {
                                return _stoped || (!_msg_list.empty() &&
                                                   _msg_list.front().when <= Clock_t::now());
                            });
                        }
                    }
                    if (!_stoped && _msg_list.empty())
                        continue;
                    if (_stoped) {
                        _msg_list.clear();
                        return;
                    }
                    // List的头结点的时间小于等于当前时间,则执行头结点任务
                    if (_msg_list.front().when <= Clock_t::now()) {
                        msg = std::move(_msg_list.front());
                        _msg_list.pop_front();
                        isFired = true;
                    }
                }
                if (isFired) {
                    dispatchMessage(msg);
                }
            }
        });
    }

    bool _stoped;
    std::string name;
    std::list<Message> _msg_list;
    std::mutex _queue_lock;
    std::condition_variable _cond;
    std::thread _looper;
    Task _callback;
    std::chrono::minutes maxSleepTime{4};
};

#endif  // _CPP_THREADHANDLER_H

Message实现类:

cpp 复制代码
#ifndef _CPP_MESSAGE_H
#define _CPP_MESSAGE_H
#include <chrono>
#include <condition_variable>
#include <functional>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <thread>

class Message {
   public:
    using TimePoint_t = std::chrono::steady_clock::time_point;
    using Clock_t = std::chrono::steady_clock;
    using MillisDuration_t = std::chrono::milliseconds;

    int what;
    int m_arg1;
    int m_arg2;
    std::function<void()> task;
    TimePoint_t when;

    Message() : Message(-1, 0) {}

    Message(int what) : Message(what, 0) {}

    Message(int what, long delayMillis)
        : what(what), when(Clock_t::now() + MillisDuration_t(delayMillis)) {
        task = nullptr;
    }

    Message(const Message& msg)
        : what(msg.what), task(msg.task), when(msg.when) {}

    Message(Message&& msg) : what(msg.what), task(msg.task), when(msg.when) {}

    ~Message() {}

    Message& operator=(const Message& msg) {
        this->what = msg.what;
        this->when = msg.when;
        this->task = msg.task;

        return *this;
    }

    Message& operator=(Message&& msg) {
        this->what = msg.what;
        this->when = msg.when;
        this->task = std::move(msg.task);
        return *this;
    }

    void setWhen(long delayMillis) {
        when = Clock_t::now() + MillisDuration_t(delayMillis);
    }

    void onRun(std::function<void()>&& f) { this->task = f; }

    bool operator>(const Message& msg) const { return (this->when > msg.when); }

    bool operator<(const Message& msg) const { return (this->when < msg.when); }

    bool operator==(const Message& msg) const {
        return (this->what == msg.what) && (this->task != nullptr) &&
               (msg.task != nullptr);
    }

    bool operator==(int what) const { return (this->what == what); }
};

#endif  // _CPP_MESSAGE_H

使用方法:

//构造函数或类初始化中设置如下

mHandler.setName("classATh");

mHandler.handleMessage([&](const Message& msg) { handleMessage(msg); });

void classATh::handleMessage(const Message& msg) {

if (msg.what == MSG_CODE_QUERY_DEVICE_INFO) {

//

} else if (msg.what == MSG_CODE_TRADE_INIT) {

//

} else if (msg.what == MSG_CODE_DEVICE_HEART_BEAT) {

heartBeat();

}

}

void classATh::startHearBeat() {

mHandler.removeMessages(MSG_CODE_DEVICE_HEART_BEAT);

mHandler.sendEmptyMessageDelay(MSG_CODE_DEVICE_HEART_BEAT, 60 * 1000);

}

相关推荐
梓仁沐白1 小时前
ubuntu+windows双系统切换后蓝牙设备无法连接
windows·ubuntu
‘’林花谢了春红‘’4 小时前
C++ list (链表)容器
c++·链表·list
九鼎科技-Leo5 小时前
什么是 WPF 中的依赖属性?有什么作用?
windows·c#·.net·wpf
机器视觉知识推荐、就业指导5 小时前
C++设计模式:建造者模式(Builder) 房屋建造案例
c++
长亭外的少年6 小时前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin
Yang.997 小时前
基于Windows系统用C++做一个点名工具
c++·windows·sql·visual studio code·sqlite3
熬夜学编程的小王7 小时前
【初阶数据结构篇】双向链表的实现(赋源码)
数据结构·c++·链表·双向链表
zz40_7 小时前
C++自己写类 和 运算符重载函数
c++
我不瘦但很逗8 小时前
Windows下使用DBeaver连接云数据库(MySQL)
数据库·windows