从 boost::threads 到 boost::asio 定时器
Posted
技术标签:
【中文标题】从 boost::threads 到 boost::asio 定时器【英文标题】:From boost::threads to boost::asio timers 【发布时间】:2012-03-17 01:31:16 【问题描述】:在我的项目中,每个类对象都有自己的线程,内部有无限循环 (while(1)),其中执行特定的对象功能。我正在尝试改变这一点,以便每个对象都可以使用计时器异步执行其功能。
基本上这就是它与无限循环的线程的工作方式:
class obj
public:
obj();
~obj();
//custom functions and variables
int x;
int obj_action;
move();
wait();
obj()
obj_action=1;
//when constructing object, make its thread with infinite while cycle
boost::thread make_thread(boost::bind(&obj::obj_engine,this));
void obj::obj_engine()
while(true)
if (obj_action==1)move();
else if (obj_action==2)wait();
Sleep(1);
void obj::move()
x++;
obj_action==2;
void obj::wait()
Sleep(5000);
obj_action==1;
这个例子展示了 obj 类,它有构造函数、析构函数、一对变量和一对函数。 在构造对象(obj())时,会创建线程。线程包含一个函数“obj_engine”,它有无限循环(while(true))。在循环中有两个功能: 1. wait() - 使线程休眠 5 秒。 2. walk() - 简单的 x+1 这两个函数在结束后通过定义 obj_action 相互切换。
现在我想将其更改为,在构造和对象时,将执行异步 move() 函数,在 move() 函数之后,将执行异步 wait() 函数,反之亦然。所以我不需要使用任何线程。
我希望得到这样的结果:
//constructing
obj()
asynchronous(walk());
walk()
x++
asynchronous(wait());
wait()
Sleep(5000);
asynchronous(walk());
我听说你可以用 boost::asio timers 做到这一点,但我真的不知道怎么做。 如果有人能告诉我怎么做,我将不胜感激。
【问题讨论】:
请查看我的答案的更新,因为我现在修复的初始源代码中存在内存泄漏。对不起。 【参考方案1】:给你:
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/bind.hpp>
#include <iostream>
class obj
public:
obj() : x_(0), t_(io_service_, boost::posix_time::seconds(5))
t_.async_wait(boost::bind(&obj::move, this));
io_service_.run();
void move()
x_++;
std::cout << x_ << std::endl;
t_.expires_at(t_.expires_at() + boost::posix_time::seconds(5));
t_.async_wait(boost::bind(&obj::move, this));
private:
int x_;
boost::asio::io_service io_service_;
boost::asio::deadline_timer t_;
;
int main(int, char**)
obj a;
while(true);
asio 教程基本上涵盖了您需要的所有内容:this tutorial shows you how to use an asynchronous timer 和 this tutorial shows you how to reset your timer。
更新:
请使用上面的源代码而不是我最初的源代码 - 由于io_service_.run()
的重复调用,每个move
调用都会在另一个线程中调用,一段时间后您的应用程序会因此而崩溃。上面的代码解决了这个问题,并通过这样做摆脱了wait
函数。
【讨论】:
但如果我尝试添加更多对象:obj a;obj b;obj c;我得到的结果是它的构造函数永远不会完成初始化。我希望每个对象都分别执行这些功能,现在它只打印第一个对象 x++ (1,2,3,4,5) 我期待的结果类似于:(111,222,333,444,555) - 如果我使用我的示例带螺纹。【参考方案2】:借用 nijansen 的示例,我整理了一些应该更类似于您想要的东西(我认为)。
这里的关键是io_service应该在所有对象的调度之间共享就可以了。通常每个线程有一个 io_service,但也可以使用更复杂的方案。 io_service::run
只要在 io_service 上安排了工作(等待超时或等待套接字),就会运行。当没有更多的工作被安排时,它只是返回。
您可能对 io_service::post
感兴趣,因为它可以作为在“活动对象”之间发送消息的一种方式(即使它们在不同的 io_services 和不同的线程下运行也能正常工作)。您可能想查看boost::bind
和可能的boost::signals
。
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/bind.hpp>
#include <iostream>
namespace asio = boost::asio;
class obj
public:
obj(asio::io_service& ioSvc)
: x_(0), t_(ioSvc)
schedule_in(5);
void schedule_in(int seconds)
t_.expires_from_now(boost::posix_time::seconds(3));
t_.async_wait(boost::bind(&obj::move, this));
void move()
x_++;
std::cout << x_ << std::endl;
schedule_in(5);
private:
int x_;
boost::asio::deadline_timer t_;
;
int main(int, char**)
boost::asio::io_service io_service;
obj a(io_service);
obj b(io_service);
obj c(io_service);
io_service.run();
【讨论】:
非常感谢。我的最后一个问题是:在游戏服务器的每个对象中使用同步计时器是否比线程更好?我所说的“更好”是指效率、更少的内存使用,以及哪种变体更受欢迎? 我绝对不会为每个对象保留一个线程。部分地,对于许多对象(数百或数千),开销,同步成为一个真正的问题。此外,即使对于少数对象,线程之间的同步和通信也会变得非常棘手。如果它真的是您正在编写的服务器,那么异步 IO 模型绝对是要走的路。它已被证明可以很好地扩展,并且是“事件”处理的不错模型。如果您的服务器执行 CPU 密集型任务,您可以将 io_service 拆分为多个线程,或者让后台线程池完成繁重的工作。以上是关于从 boost::threads 到 boost::asio 定时器的主要内容,如果未能解决你的问题,请参考以下文章