前言:
一直使用android的Handler,非常方便好用,但是当我使用C++编程时,想使用Android Handler一样的编程模式,竟不知如何下手,网上找了很久,都没找到具体的实现,也可能是我找的不够多。这两天沉下心来自己写了一个,省的自己去找了,以后肯定还能用到,最好有网友也做了类似实现,我可以借鉴下以提升自己。
代码参考Android Handler,有兴趣的朋友可以去看看Android 里面的实现。Android Handler 使用epoll 实现,我这里做了个简化版本,使用条件变量实现。
handler.h
#pragma once
#include "message.h"
#include <chrono>
#include <condition_variable>
#include <functional>
#include <list>
#include <map>
#include <mutex>
#include <thread>
using namespace std;
/*
* Handler will run in it's own thread, you don't want to care about it.
* Message will be proccess by the Handler. Two ways to add your task to the Handler.
* 1. send message to the handler
* 2. post the task(Function) to handler
*/
namespace es {
class Handler {
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)>;
Handler();
~Handler() {
is_stop = true;
condition.notify_all();
looper.join();
}
bool sendEmptyMessageDelay(int what, long delayMillis);
bool sendEmptyMessageDelay(int what) { return sendEmptyMessageDelay(what, 0); }
bool postDelay(function<void()> &&f, long delayMillis);
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_mutex);
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_mutex);
if (!msg_list.empty()) msg_list.clear();
}
void stop() {
is_stop = true;
condition.notify_one();
}
void handleMessage(Task &&cb) { callback = cb; }
private:
void dispatchMessage(const Message &msg) const;
private:
bool is_stop;
list<Message> msg_list;
mutex queue_mutex;
condition_variable condition;
thread looper;
Task callback;
};
} // namespace es
handler.cc
#include "handler.h"
#include "message.h"
#include <algorithm>
#include <chrono>
#include <iostream>
namespace es {
Handler::Handler()
: is_stop(false), looper([this]() {
for (;;) {
Message msg;
bool isFired = false;
{
std::unique_lock<std::mutex> lock(this->queue_mutex);
if (this->msg_list.empty()) {
this->condition.wait(lock, [this] { return this->is_stop || !this->msg_list.empty(); });
} else {
this->condition.wait_until(lock, this->msg_list.front().when,
[this] { return this->is_stop || this->msg_list.empty(); });
}
if (!is_stop && this->msg_list.empty()) continue;
if (is_stop) {
msg_list.clear();
return;
}
if (msg_list.front().when < Clock_t::now()) {
msg = std::move(msg_list.front());
msg_list.pop_front();
isFired = true;
}
}
if (isFired) this->dispatchMessage(msg);
}
}) {}
bool Handler::sendEmptyMessageDelay(int what, long delayMillis) {
if (what < 0 || delayMillis < 0) return false;
Message msg(what, delayMillis);
std::unique_lock<std::mutex> lock(queue_mutex);
msg_list.push_back(msg);
// 跟进时间进行降序排列
msg_list.sort(std::less<Message>());
condition.notify_one();
return true;
}
bool Handler::postDelay(std::function<void()> &&f, long delayMillis) {
if (f == nullptr || delayMillis < 0) {
return false;
}
std::unique_lock<std::mutex> lock(queue_mutex);
Message msg(0, delayMillis);
msg.onRun(std::move(f));
msg_list.push_back(msg);
msg_list.sort(std::less<Message>());
return true;
}
void Handler::dispatchMessage(const Message &msg) const {
if (msg.task != nullptr) {
msg.task();
} else {
if (msg.what < 0 || callback == nullptr) return;
callback(msg);
}
}
} // namespace es
使用:
#include <iostream>
#include <memory>
#include "handler.h"
#include "message.h"
using namespace std;
using namespace es;
int main(int argc, char **argv) {
cout << "Handler tutorial" << endl;
Handler hdlr;
hdlr.handleMessage([](const Message &msg) {
switch (msg.what) {
case 0: break;
case 1: break;
default: break;
}
cout << "Handler what: " << msg.what << endl;
});
for (int i = 0; i < 6; i++) {
hdlr.sendEmptyMessageDelay(i + 1, 1000 * i);
}
hdlr.postDelay([]() { cout << "POST call back" << endl; }, 230);
std::this_thread::sleep_until(std::chrono::steady_clock::now() + std::chrono::seconds(3));
hdlr.removeMessages(6);
std::this_thread::sleep_until(std::chrono::steady_clock::now() + std::chrono::seconds(1));
hdlr.removeAlls();
// hdlr.stop();
cout << "Program exit !" << endl;
return 1;
}
这里只帖出Handler的实现,还有个配套的Message实现,感兴趣的童鞋自己去下面链接查看吧。
代码链接:https://github.com/feekia/EventServer
另,转载请注明出处:CSDN