http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-
started-with-boostasio?pg=7
6 定时器
boost::asio 提供了一个 deadline_timer class来提供同步与异步的接口。
BOOST文档提供了一组优秀示例。
第一个例子,将创建一个间隔5秒的定时器。
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <iostream>
boost::mutex global_stream_lock;
void WorkerThread(boost::shared_ptr< boost::asio::io_service >
io_service)
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Thread Start" << std::endl;
global_stream_lock.unlock();
while (true)
{
try
{
boost::system::error_code ec;
io_service->run(ec);
if (ec)
{
global_stream_lock.lock();
std::cout << "[" <<
boost::this_thread::get_id()
<< "] Error: " << ec <<
std::endl;
global_stream_lock.unlock();
}
break;
}
catch (std::exception & ex)
{
global_stream_lock.lock();
std::cout << "[" <<
boost::this_thread::get_id()
<< "] Exception: " << ex.what() <<
std::endl;
global_stream_lock.unlock();
}
}
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Thread Finish" << std::endl;
global_stream_lock.unlock();
}
void TimerHandler(const boost::system::error_code & error)
{
if (error)
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Error: " << error << std::endl;
global_stream_lock.unlock();
}
else
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] TimerHandler " << std::endl;
global_stream_lock.unlock();
}
}
int main(int argc, char * argv[])
{
boost::shared_ptr< boost::asio::io_service > io_service(
new boost::asio::io_service
);
boost::shared_ptr< boost::asio::io_service::work > work(
new boost::asio::io_service::work(*io_service)
);
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Press [return] to exit." << std::endl;
global_stream_lock.unlock();
boost::thread_group worker_threads;
for (int x = 0; x < 2; ++x)
{
worker_threads.create_thread(boost::bind
(&WorkerThread, io_service));
}
boost::asio::deadline_timer timer(*io_service);
timer.expires_from_now(boost::posix_time::seconds(5));
timer.async_wait(TimerHandler);
std::cin.get();
io_service->stop();
worker_threads.join_all();
return 0;
}
如果我们想创建一个可冲用的定时器.我们将定时器对象设置为全局,但是可能
导致共享对象不是线程安全的。boost::bind能解决这个问题。使用定时器对象
的shared_ptr指针,我们能使用bind并且传递定时器到指定的handler,保持定
时器可重用。
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <iostream>
boost::mutex global_stream_lock;
void WorkerThread(boost::shared_ptr< boost::asio::io_service >
io_service)
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Thread Start" << std::endl;
global_stream_lock.unlock();
while (true)
{
try
{
boost::system::error_code ec;
io_service->run(ec);
if (ec)
{
global_stream_lock.lock();
std::cout << "[" <<
boost::this_thread::get_id()
<< "] Error: " << ec <<
std::endl;
global_stream_lock.unlock();
}
break;
}
catch (std::exception & ex)
{
global_stream_lock.lock();
std::cout << "[" <<
boost::this_thread::get_id()
<< "] Exception: " << ex.what() <<
std::endl;
global_stream_lock.unlock();
}
}
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Thread Finish" << std::endl;
global_stream_lock.unlock();
}
void TimerHandler(
const boost::system::error_code & error,
boost::shared_ptr< boost::asio::deadline_timer > timer
)
{
if (error)
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Error: " << error << std::endl;
global_stream_lock.unlock();
}
else
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] TimerHandler " << std::endl;
global_stream_lock.unlock();
timer->expires_from_now(boost::posix_time::seconds
(5));
timer->async_wait(boost::bind(&TimerHandler, _1,
timer));
}
}
int main(int argc, char * argv[])
{
boost::shared_ptr< boost::asio::io_service > io_service(
new boost::asio::io_service
);
boost::shared_ptr< boost::asio::io_service::work > work(
new boost::asio::io_service::work(*io_service)
);
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Press [return] to exit." << std::endl;
global_stream_lock.unlock();
boost::thread_group worker_threads;
for (int x = 0; x < 2; ++x)
{
worker_threads.create_thread(boost::bind
(&WorkerThread, io_service));
}
boost::shared_ptr< boost::asio::deadline_timer > timer(
new boost::asio::deadline_timer(*io_service)
);
timer->expires_from_now(boost::posix_time::seconds(5));
timer->async_wait(boost::bind(&TimerHandler, _1, timer));
std::cin.get();
io_service->stop();
worker_threads.join_all();
return 0;
}
使用bind可以做许多有趣的事情,_1参数是一个占位符。因为TimerHandler 函
数需要一个参数用于回调,我们需要引用这个bind调用。_1意味着第一个参数,
我们稍后提供。
运行上面例子,我们将获得一个每五秒激活一次的定时器。
如果想保证定时器不和work处理器同时运行,我们可以使用strand。
代码如下
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <iostream>
boost::mutex global_stream_lock;
void WorkerThread(boost::shared_ptr< boost::asio::io_service > io_service)
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Thread Start" << std::endl;
global_stream_lock.unlock();
while (true)
{
try
{
boost::system::error_code ec;
io_service->run(ec);
if (ec)
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Error: " << ec << std::endl;
global_stream_lock.unlock();
}
break;
}
catch (std::exception & ex)
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Exception: " << ex.what() << std::endl;
global_stream_lock.unlock();
}
}
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Thread Finish" << std::endl;
global_stream_lock.unlock();
}
void TimerHandler(
const boost::system::error_code & error,
boost::shared_ptr< boost::asio::deadline_timer > timer,
boost::shared_ptr< boost::asio::io_service::strand > strand
)
{
if (error)
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Error: " << error << std::endl;
global_stream_lock.unlock();
}
else
{
std::cout << "[" << boost::this_thread::get_id()
<< "] TimerHandler " << std::endl;
timer->expires_from_now(boost::posix_time::seconds(1));
timer->async_wait(
strand->wrap(boost::bind(&TimerHandler, _1, timer, strand))
);
}
}
void PrintNum(int x)
{
std::cout << "[" << boost::this_thread::get_id()
<< "] x: " << x << std::endl;
boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
}
int main(int argc, char * argv[])
{
boost::shared_ptr< boost::asio::io_service > io_service(
new boost::asio::io_service
);
boost::shared_ptr< boost::asio::io_service::work > work(
new boost::asio::io_service::work(*io_service)
);
boost::shared_ptr< boost::asio::io_service::strand > strand(
new boost::asio::io_service::strand(*io_service)
);
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Press [return] to exit." << std::endl;
global_stream_lock.unlock();
boost::thread_group worker_threads;
for (int x = 0; x < 2; ++x)
{
worker_threads.create_thread(boost::bind(&WorkerThread, io_service));
}
boost::this_thread::sleep(boost::posix_time::seconds(1));
strand->post(boost::bind(&PrintNum, 1));
strand->post(boost::bind(&PrintNum, 2));
strand->post(boost::bind(&PrintNum, 3));
strand->post(boost::bind(&PrintNum, 4));
strand->post(boost::bind(&PrintNum, 5));
boost::shared_ptr< boost::asio::deadline_timer > timer(
new boost::asio::deadline_timer(*io_service)
);
timer->expires_from_now(boost::posix_time::seconds(1));
timer->async_wait(
strand->wrap(boost::bind(&TimerHandler, _1, timer, strand))
);
std::cin.get();
io_service->stop();
worker_threads.join_all();
return 0;
}
我们需要使用strand封装定时器处理器,strand能确保工作对象先运行而后定时器线程后运行。
本章节我们学习如何使用bind strand shard_ptr来获取灵活性和实现功能。在后面的网络系统中我们将使用这些组件。