2012-03-17 59 views
1

在我的項目中,每個類對象都有自己的線程,其中有無限循環(while(1)),其中執行了特定的對象函數。我試圖改變這一點,以便每個對象都可以與定時器異步執行其功能。從boost :: threads到boost :: asio定時器

基本上這是它如何與線程與無限循環的工作原理:

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()); 
} 

我聽說你能做到這一點,用升壓:: ASIO計時器,但我真的不知道怎麼辦。 如果有人會告訴我如何,我將非常感激。

+0

請看我的答案的更新,因爲在我現在修復的初始源代碼中存在內存泄漏。抱歉。 – nijansen 2012-03-17 10:35:53

回答

2

在這裏你去:this tutorial shows you how to use an asynchronous timer,並且this tutorial shows you how to reset your timer

#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教程覆蓋。

更新:

請使用上面的源代碼,而不是我最初之一 - 由於io_service_.run()的重複調用,每個move調用將在另一個線程調用,並在一段時間後您的應用程序,因爲崩潰的。上面的代碼修復了這個問題,並通過這樣做來消除wait函數。

+0

但是,如果我嘗試添加更多的對象: obj a; obj b; obj c; 我得到的結果是,它的構造函數從未完成初始化。我希望每個對象都可以單獨執行這些函數,現在它只打印第一個對象x ++(1,2,3,4,5) 我期待得到如下結果:(111,222,333,444,555) - 如果我使用我的線程示例。 – 2012-03-17 13:08:37

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(); 
} 
+0

非常感謝。我的最後一個問題是:在遊戲服務器的每個對象中使用同步定時器比線程更好嗎?通過說「更好」我的意思是效率,更少的內存使用,哪一個更受歡迎? – 2012-03-17 22:08:24

+1

我絕對不會爲每個對象保留一個線程。部分地,對​​於很多對象(數百或數千),開銷,同步成爲一個真正的問題。而且,即使對於很少的對象,線程之間的同步和通信也可能變得非常棘手。 如果它確實是您正在編寫的服務器,那麼異步IO模型絕對是您的選擇。它已被證明可以很好地擴展,並且對於「事件」處理來說是一個體面的模型。 如果您的服務器執行CPU密集型任務,則可以將io_service拆分爲多個線程,或讓後臺線程池完成繁重任務。 – Rawler 2012-03-18 14:57:46