mirror of
https://gitee.com/acl-dev/acl.git
synced 2024-12-03 20:38:11 +08:00
9697f95b8f
This reverts commit 15d999759e
.
309 lines
6.0 KiB
C++
309 lines
6.0 KiB
C++
#pragma once
|
|
#include "../acl_cpp_define.hpp"
|
|
#include <map>
|
|
#include <vector>
|
|
#include "noncopyable.hpp"
|
|
#include "mbox.hpp"
|
|
#include "util.hpp"
|
|
#include "thread.hpp"
|
|
#include "thread_mutex.hpp"
|
|
|
|
namespace acl {
|
|
|
|
/**
|
|
* 具有相同时间截的定时任务的集合
|
|
*/
|
|
template <typename T>
|
|
class trigger_item : public noncopyable
|
|
{
|
|
public:
|
|
typedef std::map<long long, trigger_item<T>*> trigger_items_t;
|
|
|
|
trigger_item(trigger_items_t& items) : items_(items) {}
|
|
~trigger_item(void) {}
|
|
|
|
/**
|
|
* 添加一个定时任务
|
|
* @pararm o {T*}
|
|
*/
|
|
void add(T* o)
|
|
{
|
|
objs_.push_back(o);
|
|
}
|
|
|
|
/**
|
|
* 删除一个具有相同时间截的定时任务
|
|
* @pararm o {T*}
|
|
* @return {int} 返回值 >= 0 表示剩余的具有相同时间截的定时任务数,
|
|
* 返回 -1 表示该定时任务不存在
|
|
*/
|
|
int del(T* o)
|
|
{
|
|
for (typename std::vector<T*>::iterator it = objs_.begin();
|
|
it != objs_.end(); ++it) {
|
|
|
|
if (*it == o) {
|
|
objs_.erase(it);
|
|
return (int) objs_.size();
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* 获取具有相同时间截的所有定时任务集合
|
|
* @return {std::vector<T*>&}
|
|
*/
|
|
std::vector<T*>& get_objs(void)
|
|
{
|
|
return objs_;
|
|
}
|
|
|
|
private:
|
|
std::vector<T*> objs_;
|
|
trigger_items_t& items_;
|
|
};
|
|
|
|
/**
|
|
* 定时任务触发管理器,通过本类添加定时任务,该类会将到期的任务进行触发
|
|
* 每个定时任务对象 T 需要实现以下方法,以便于由该触发器触发
|
|
*
|
|
* bool on_trigger(void); // 定时时间到期时的回调方法,返回值表示
|
|
* // 是否需要再次触发该定时任务
|
|
* int get_ttl(void) const; // 定时任务到达时的时间间隔(毫秒)
|
|
* void set_key(long long key); // 触发器设置与该定时任务关联的键
|
|
* long long get_key(void) const; // 获得由 set_key 设置的键
|
|
*
|
|
* 如一个 T 的实例类声明如下:
|
|
* class mytask
|
|
* {
|
|
* public:
|
|
* mytask(void) {}
|
|
* ~mytask(void) {}
|
|
*
|
|
* // @override
|
|
* bool on_trigger(void)
|
|
* {
|
|
* return true;
|
|
* }
|
|
*
|
|
* // @override
|
|
* int get_ttl(void) const
|
|
* {
|
|
* return 1000;
|
|
* }
|
|
*
|
|
* // @override
|
|
* void set_key(long long key)
|
|
* {
|
|
* key_ = key;
|
|
* }
|
|
*
|
|
* // @override
|
|
* long long get_key(void) const
|
|
* {
|
|
* return key_;
|
|
* }
|
|
*
|
|
* private:
|
|
* long long key_;
|
|
* };
|
|
*/
|
|
template <typename T>
|
|
class timer_trigger : public noncopyable
|
|
{
|
|
public:
|
|
typedef std::map<long long, trigger_item<T>*> trigger_items_t;
|
|
typedef typename trigger_items_t::iterator trigger_iter_t;
|
|
|
|
timer_trigger(void) {}
|
|
~timer_trigger(void) {}
|
|
|
|
/**
|
|
* 添加一个任务对象
|
|
* @pararm o {T*}
|
|
*/
|
|
void add(T* o)
|
|
{
|
|
int ttl = o->get_ttl();
|
|
long long key = get_curr_stamp() + ttl;
|
|
|
|
trigger_item<T>* item;
|
|
trigger_iter_t it = items_.find(key);
|
|
if (it == items_.end()) {
|
|
item = new trigger_item<T>(items_);
|
|
items_[key] = item;
|
|
} else
|
|
item = it->second;
|
|
item->add(o);
|
|
o->set_key(key);
|
|
}
|
|
|
|
/**
|
|
* 删除一个任务对象,内部调用 o->get_key() 方法获得该任务对象的键
|
|
* @pararm o {T*} 指定将被删除的任务对象
|
|
* @return {int} >= 0 时表示剩余的任务对象,-1 表示该任务对象不存在
|
|
*/
|
|
int del(T* o)
|
|
{
|
|
long long key = o->get_key();
|
|
trigger_iter_t it = items_.find(key);
|
|
|
|
if (it == items_.end())
|
|
return -1;
|
|
if (it->second->del(o) == 0) {
|
|
delete it->second;
|
|
items_.erase(it);
|
|
}
|
|
return (int) items_.size();
|
|
}
|
|
|
|
/**
|
|
* 触发所有到期的定时任务
|
|
* @return {long long} 返回下一个将被触发的定时任务的时间截,返回 -1
|
|
* 表示没有定时任务
|
|
*/
|
|
long long trigger(void)
|
|
{
|
|
long long key = get_curr_stamp();
|
|
std::vector<trigger_item<T>*> items;
|
|
trigger_iter_t iter;
|
|
for (iter = items_.begin(); iter != items_.end();) {
|
|
if (iter->first > key)
|
|
break;
|
|
|
|
items.push_back(iter->second);
|
|
items_.erase(iter++);
|
|
}
|
|
|
|
for (typename std::vector<trigger_item<T>*>::iterator
|
|
it = items.begin(); it != items.end(); ++it) {
|
|
|
|
trigger(*it);
|
|
delete *it;
|
|
}
|
|
|
|
iter = items_.begin();
|
|
if (iter == items_.end())
|
|
return -1;
|
|
return iter->first;
|
|
}
|
|
|
|
private:
|
|
trigger_items_t items_;
|
|
|
|
/**
|
|
* 触发具有相同定时时间截的所有任务
|
|
* @pararm item {trigger_item<T>*}
|
|
*/
|
|
void trigger(trigger_item<T>* item)
|
|
{
|
|
std::vector<T*>& objs = item->get_objs();
|
|
for (typename std::vector<T*>::iterator it = objs.begin();
|
|
it != objs.end(); ++it) {
|
|
|
|
if (!(*it)->on_trigger())
|
|
continue;
|
|
|
|
int ttl = (*it)->get_ttl();
|
|
long long key = get_curr_stamp() + ttl;
|
|
|
|
trigger_iter_t iter = items_.find(key);
|
|
if (iter == items_.end()) {
|
|
item = new trigger_item<T>(items_);
|
|
items_[key] = item;
|
|
} else
|
|
item = iter->second;
|
|
|
|
item->add(*it);
|
|
(*it)->set_key(key);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 定时器管理线程,该线程从 mbox 中获得定时任务,并加入定时任务触发器中,然后
|
|
* 定时从触发器中提取到期的任务并触发
|
|
*/
|
|
template <typename T>
|
|
class thread_trigger : public thread
|
|
{
|
|
public:
|
|
thread_trigger(void)
|
|
: delay_(100) // 初始化时的超时等待时间(毫秒)
|
|
, stop_(false) // 是否停止线程
|
|
{
|
|
}
|
|
|
|
virtual ~thread_trigger(void) {}
|
|
|
|
/**
|
|
* 添加一个定时任务对象
|
|
* @pararm o {T*}
|
|
*/
|
|
void add(T* o)
|
|
{
|
|
mbox_.push(o);
|
|
}
|
|
|
|
/**
|
|
* 添加要删除的定时任务对象到临时队列中,然后从定时器中删除之
|
|
* @pararm o {T*}
|
|
*/
|
|
void del(T* o)
|
|
{
|
|
lock_.lock();
|
|
timer_del_.push_back(o);
|
|
lock_.unlock();
|
|
}
|
|
|
|
timer_trigger<T>& get_trigger(void)
|
|
{
|
|
return timer_;
|
|
}
|
|
|
|
private:
|
|
// @override
|
|
void* run(void)
|
|
{
|
|
while (!stop_) {
|
|
T* o = mbox_.pop(delay_);
|
|
if (o)
|
|
timer_.add(o);
|
|
|
|
long long next = timer_.trigger();
|
|
long long curr = get_curr_stamp();
|
|
if (next == -1)
|
|
delay_ = 100;
|
|
else {
|
|
delay_ = next - curr;
|
|
if (delay_ < 0)
|
|
delay_ = 1;
|
|
}
|
|
|
|
lock_.lock();
|
|
typename std::vector<T*>::iterator it;
|
|
for (it = timer_del_.begin();
|
|
it != timer_del_.end(); ++it) {
|
|
|
|
timer_.del(*it);
|
|
}
|
|
timer_del_.clear();
|
|
lock_.unlock();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
private:
|
|
long long delay_;
|
|
bool stop_;
|
|
|
|
timer_trigger<T> timer_;
|
|
mbox<T> mbox_;
|
|
|
|
std::vector<T*> timer_del_;
|
|
thread_mutex lock_;
|
|
};
|
|
|
|
} // namespace acl
|