acl/lib_acl_cpp/include/acl_cpp/stdlib/trigger.hpp

320 lines
6.2 KiB
C++
Raw Normal View History

/**
* Copyright (C) 2017-2018 IQIYI
* All rights reserved.
*
* AUTHOR(S)
* Zheng Shuxin
* E-mail: zhengshuxin@qiyi.com
*
* VERSION
* Thu 07 Sep 2017 04:33:59 PM CST
*/
#pragma once
#include "../acl_cpp_define.hpp"
#include <map>
#include <vector>
#include "mbox.hpp"
#include "util.hpp"
#include "thread.hpp"
#include "thread_mutex.hpp"
namespace acl {
/**
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬʱ<EFBFBD><EFBFBD><EFBFBD>صĶ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD>
*/
template <typename T>
class trigger_item
{
public:
typedef std::map<long long, trigger_item<T>*> trigger_items_t;
trigger_item(trigger_items_t& items) : items_(items) {}
~trigger_item(void) {}
/**
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @pararm o {T*}
*/
void add(T* o)
{
objs_.push_back(o);
}
/**
* ɾ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬʱ<EFBFBD><EFBFBD><EFBFBD>صĶ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @pararm o {T*}
* @return {int} <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ >= 0 <EFBFBD><EFBFBD>ʾʣ<EFBFBD><EFBFBD><EFBFBD>ľ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬʱ<EFBFBD><EFBFBD><EFBFBD>صĶ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD> -1 <EFBFBD><EFBFBD>ʾ<EFBFBD>ö<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>񲻴<EFBFBD><EFBFBD><EFBFBD>
*/
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;
}
/**
* <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬʱ<EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>񼯺<EFBFBD>
* @return {std::vector<T*>&}
*/
std::vector<T*>& get_objs(void)
{
return objs_;
}
private:
std::vector<T*> objs_;
trigger_items_t& items_;
};
/**
* <EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>񴥷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӷ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>񣬸<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD>
* ÿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> T <EFBFBD><EFBFBD>Ҫʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ա<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɸô<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*
* bool on_trigger(void); // <20><>ʱʱ<CAB1><EFBFBD><E4B5BD>ʱ<EFBFBD>Ļص<C4BB><D8B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>ʾ
* // <20>Ƿ<EFBFBD><C7B7><EFBFBD>Ҫ<EFBFBD>ٴδ<D9B4><CEB4><EFBFBD><EFBFBD>ö<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>
* int get_ttl(void) const; // <20><>ʱ<EFBFBD><CAB1><EFBFBD>񵽴<EFBFBD>ʱ<EFBFBD><CAB1>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* void set_key(long long key); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ö<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>
* long long get_key(void) const; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> set_key <20><><EFBFBD>õļ<C3B5>
*
* <EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> T <EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>£<EFBFBD>
* 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:
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) {}
/**
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @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);
}
/**
* ɾ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> o->get_key() <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ø<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>
* @pararm o {T*} ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return {int} >= 0 ʱ<EFBFBD><EFBFBD>ʾʣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>-1 <EFBFBD><EFBFBD>ʾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>󲻴<EFBFBD><EFBFBD><EFBFBD>
*/
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();
}
/**
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD><EFBFBD>ڵĶ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return {long long} <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ķ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>أ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> -1
* <EFBFBD><EFBFBD>ʾû<EFBFBD>ж<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
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_;
/**
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬ<EFBFBD><EFBFBD>ʱʱ<EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @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);
}
}
};
/**
* <EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̣߳<EFBFBD><EFBFBD><EFBFBD><EFBFBD>̴߳<EFBFBD> mbox <EFBFBD>л<EFBFBD><EFBFBD>ö<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>񣬲<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>񴥷<EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD>Ȼ<EFBFBD><EFBFBD>
* <EFBFBD><EFBFBD>ʱ<EFBFBD>Ӵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>񲢴<EFBFBD><EFBFBD><EFBFBD>
*/
template <typename T>
class thread_trigger : public thread
{
public:
thread_trigger(void)
: delay_(100) // <20><>ʼ<EFBFBD><CABC>ʱ<EFBFBD>ij<EFBFBD>ʱ<EFBFBD>ȴ<EFBFBD>ʱ<EFBFBD><EFBFBD><E4A3A8><EFBFBD>
, stop_(false) // <20>Ƿ<EFBFBD>ֹͣ<CDA3>߳<EFBFBD>
{
}
virtual ~thread_trigger(void) {}
/**
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @pararm o {T*}
*/
void add(T* o)
{
mbox_.push(o);
}
/**
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫɾ<EFBFBD><EFBFBD><EFBFBD>Ķ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD>Ȼ<EFBFBD><EFBFBD><EFBFBD>Ӷ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɾ<EFBFBD><EFBFBD>֮
* @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