从 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 定时器的主要内容,如果未能解决你的问题,请参考以下文章

Boost Threads Producer/Consumer 意外行为

在禁用中断时中断 boost::thread

在 boost::thread 线程中使用异常

C ++ Boost:2个线程之间的变量同步

同步 STD cout 输出多线程

从 boost::process 到 boost::child 的信号传播