基于Boost::Asio的定时器模块

2 篇文章 0 订阅
1 篇文章 0 订阅

timer.hpp

#include <list>
#include <memory>
#include <mutex>
#include <boost/asio.hpp>
#include <boost/asio/deadline_timer.hpp>

typedef boost::system::error_code boost_error_code;
using namespace boost::asio;
using namespace boost;
using namespace std;
using IO_NUM = std::integral_constant<int, 32>;

class CQIoService : public asio::noncopyable
{
public:
	using Ptr = std::shared_ptr<CQIoService>;

	CQIoService(int concurrencyHint)
		:
		mTrickyIoService(std::make_shared<io_service>(concurrencyHint)),
		mIoService(*mTrickyIoService)
	{
	}

	CQIoService(io_service& ioService)
		:
		mIoService(ioService)
	{}

	virtual ~CQIoService()
	{
		stop();
	}

	void run() const
	{
		io_service::work worker(mIoService);
		for (; !mIoService.stopped();)
		{
			mIoService.run();
		}
	}

	void stop() const
	{
		mIoService.stop();
	}

	io_service& service() const
	{
		return mIoService;
	}

	auto io_callback(int timeout, std::function<void(void)> callback) const
	{
		std::chrono::nanoseconds timeout_(timeout);
		auto timer = std::make_shared<asio::steady_timer>(mIoService);
		timer->expires_from_now(timeout_);
		timer->async_wait([timer, callback](const error_code& ec) {
			if (!ec)
			{
				callback();
			}
			});
		return timer;
	}

public:
	std::shared_ptr<io_service>   mTrickyIoService;
	io_service& mIoService;
};

class CQIoServiceThread : public asio::noncopyable
{
public:
	using Ptr = std::shared_ptr<CQIoServiceThread>;

	CQIoServiceThread(int concurrencyHint)
		:
		io_(concurrencyHint)
	{
	}

	virtual ~CQIoServiceThread()
	{
		stop();
	}

	void start(size_t threadNum)
	{
		std::lock_guard<std::mutex> lck(mIoThreadGuard);
		if (threadNum == 0)
		{
			throw std::runtime_error("thread num is zero");
		}
		if (!mIoThreads.empty())
		{
			return;
		}
		for (size_t i = 0; i < threadNum; i++)
		{
			mIoThreads.push_back(std::thread([this]() {
				io_.run();
				}));
		}
	}

	void stop()
	{
		std::lock_guard<std::mutex> lck(mIoThreadGuard);

		io_.stop();
		for (auto& thread : mIoThreads)
		{
			try
			{
				thread.join();
			}
			catch (...)
			{
			}
		}
		mIoThreads.clear();
	}

	io_service& service()
	{
		return io_.service();
	}

	CQIoService& wrapperIoService()
	{
		return io_;
	}

private:
	CQIoService io_;
	std::vector<std::thread> mIoThreads;
	std::mutex mIoThreadGuard;
};

class CQIoServicePool : public asio::noncopyable
{
public:
	using Ptr = std::shared_ptr<CQIoServicePool>;

	CQIoServicePool(size_t poolSize,
		int concurrencyHint)
		:
		mPickIoServiceIndex(0)
	{
		if (poolSize == 0)
		{
			throw std::runtime_error("pool size is zero");
		}

		for (size_t i = 0; i < poolSize; i++)
		{
			mIoServicePool.emplace_back(std::make_shared<CQIoServiceThread>(concurrencyHint));
		}
	}

	virtual ~CQIoServicePool()
	{
		stop();
	}

	void  set_threadNum_everyService(size_t threadNumEveryService)
	{
		std::lock_guard<std::mutex> lck(mPoolGuard);

		for (const auto& service : mIoServicePool)
		{
			service->start(threadNumEveryService);
		}
	}

	void stop()
	{
		std::lock_guard<std::mutex> lck(mPoolGuard);

		for (const auto& service : mIoServicePool)
		{
			service->stop();
		}
		mIoServicePool.clear();
	}

	io_service& pickIoService()
	{
		const auto index = mPickIoServiceIndex.fetch_add(1, std::memory_order::memory_order_relaxed);
		return mIoServicePool[index % mIoServicePool.size()]->service();
	}

	CQIoServiceThread::Ptr pickIoServiceThread()
	{
		const auto index = mPickIoServiceIndex.fetch_add(1, std::memory_order::memory_order_relaxed);
		return mIoServicePool[index % mIoServicePool.size()];
	}

private:
	std::vector<CQIoServiceThread::Ptr>   mIoServicePool;
	std::mutex                            mPoolGuard;
	std::atomic_int32_t                   mPickIoServiceIndex;
};

class CQIoServiceManager
{
public:
	static CQIoServiceManager* obj()
	{
		static CQIoServiceManager instance;
		return &instance;
	}

	CQIoServicePool::Ptr& get_io_service_pool() { return ios_; }

	io_service& get_io_service() const { return ios_->pickIoService(); }

	void stop() const { ios_->stop(); }
private:
	CQIoServiceManager()
	{
		ios_ = std::make_shared<CQIoServicePool>(IO_NUM::value, 1);
		ios_->set_threadNum_everyService(1);
	}
	~CQIoServiceManager() = default;

	CQIoServicePool::Ptr ios_;
};

template<typename ObjType>
class CQTimer
{
	using TimerCallBack = std::function<void(const boost_error_code&, ObjType&)>;
public:
	CQTimer(int millseconds, const ObjType& t, const TimerCallBack& func)
		:_timer(CQIoServiceManager::obj()->get_io_service()), _millseconds(millseconds), _isCancelled(false)
	{
		this->setTimer(t, func);
	}

	void cancel()
	{
		if (_isCancelled)
			return;
		_timer.cancel();
		_isCancelled = true;
	}

	ObjType getObj() { return _t; }

private:
	void start(const TimerCallBack& func)
	{
		_timer.expires_from_now(posix_time::milliseconds(_millseconds));
		_timer.async_wait(std::bind(func, std::placeholders::_1, this->_t));
	}

	void setTimer(const ObjType& t, const TimerCallBack& func)
	{
		_t = t;
		this->start(func);
	}

private:
	deadline_timer _timer;
	int _millseconds;

	ObjType _t;
	bool _isCancelled;
};

template<typename ObjType>
class CQTimer_List
{
	using CQTimer_Ptr = std::shared_ptr<CQTimer<ObjType>>;

	// 这种定时器回调只有false(超时) 与 true(人为提前取消)两个状态
	using TimerCallBackBool = std::function<void(bool, ObjType&)>;

	// 这种定时器回调不仅可以知道是超时还是提前取消,还可以知道错误信息,可以用if来判断,行为上与上面那个接口一样
	using TimerCallBackBsec = std::function<void(const boost_error_code&, ObjType&)>;
private:
	std::mutex mu;
	std::list<CQTimer_Ptr> timer_list;
	TimerCallBackBool _tcbBool;

public:
	void putInTimerList(const CQTimer_Ptr& t)
	{
		std::unique_lock<std::mutex> lock(mu);
		timer_list.push_back(t);
	}
	// 如未查到相应对象,则返回空指针的对象
	CQTimer_Ptr getFromTimerList(const ObjType& t, bool isLast = false)
	{
		std::unique_lock<std::mutex> lock(mu);
		CQTimer_Ptr rc;
		auto it = timer_list.begin();
		for (; it != timer_list.end(); ++it)
		{
			if ((*it)->getObj() == t)
			{
				rc = *it;
				timer_list.erase(it);
				break;
			}
		}

		return rc;
	}

	void timerCallBack(const boost_error_code& ec, ObjType& ot)
	{
		if (ec)_tcbBool(true, ot);
		else _tcbBool(false, ot);
	}

	void runTimer(int timeout_ms, const ObjType& t, const TimerCallBackBool &func)
	{
		_tcbBool = func;
		const TimerCallBackBsec func2 = std::bind(
			&CQTimer_List::timerCallBack, this, std::placeholders::_1, std::placeholders::_2);
		CQTimer_Ptr ot(new CQTimer<ObjType>(timeout_ms, t, func2));
		putInTimerList(ot);//做定时器
	}

	void runTimer(int timeout_ms, const ObjType& t, const TimerCallBackBsec &func)
	{
		CQTimer_Ptr ot(new CQTimer<ObjType>(timeout_ms, t, func));
		putInTimerList(ot);//做定时器
	}
};

 

 

test.cpp

 

#include <iostream>
#include <thread>
#include "timer.hpp"
using namespace std;

using TYPE = int;

auto ctl = std::make_shared<CQTimer_List<TYPE>>();
using TimerCallBack = std::function<void(bool, TYPE)>;

void TimerCallBackHandle(bool rs, TYPE t)
{
    if (rs) {
        cout << "消息: "<< t << " 正常取消定时!" << endl;
        return;
    }
    cout << "消息: " << t << " 超时了!" << endl;
}

void func()
{
    for (int i = 10; i < 50; ++i) {
        auto timer = ctl->getFromTimerList(i);
        if (timer)timer->cancel();
    }
}

int main()
{
    const TimerCallBack tcb = TimerCallBackHandle;
    
    // 对id:0-99999 进行定时
    for (int i = 0; i < 100000; ++i) {
        ctl->runTimer(3000, i, tcb);
    }
    
    // 取消部分id的定时
    std::thread th(&func);
    th.detach();

    //程序保活
    while(true) {
        sleep(1000);
    }

    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

dqsjqian

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

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

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

打赏作者

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

抵扣说明:

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

余额充值