2011-12-15 148 views
5

永久運行並處理請求的服務器需要一個異步部分的代碼,它將執行一些數據庫查詢,並且只有在有任何新的更改時才進行更新。服務器必須永遠運行,並且這個一次又一次地執行db函數的函數必須異步運行,這樣服務器就不會因爲每x分鐘更新一次而受到阻礙。C++中的異步處理

如何在C++中異步處理這個問題?我怎樣才能將這個函數單獨設置爲在守護進程上運行,以便它根本不會阻塞服務器?

+0

多線程程序如何? – 2011-12-15 23:14:05

+6

你檢查過Boost ASIO嗎?有同步和異步IO,定時器等等。 http://www.boost.org/doc/libs/release/libs/asio/ – Joel 2011-12-15 23:17:50

+0

使用線程方法。我可以將該線程設置爲守護程序,就像它在python中完成的一樣嗎?因爲程序的其餘部分實際上並不需要線程作爲它的CORBA。 @Joel來ASIO,請賜教。它看起來像一個很好的選擇(我對asio知之甚少),但似乎阻止了對io_service.run()的調用。無論服務器做什麼,我都想定期異步運行dbqueries函數。除非他們要共享一個變量,否則它們幾乎是分離的。服務器繼續運行時,另一個函數必須異步運行。 – King 2011-12-15 23:58:49

回答

5

我強烈建議使用Boost's ASIO庫

你需要一個類來接受新的請求,另一個是定期檢查更新。兩者都可以異步完成工作,並使用相同的boost :: asio :: io_service來安排工作。

的設置將

  • 網絡異步boost::asio::ip::tcp::acceptor偵聽新的請求。
  • A boost::asio::deadline_time做異步等待檢查更新數據庫。

僞什麼,我明白你的描述代碼如下:

#include <iostream> 
#include <boost/asio.hpp> 
#include <boost/bind.hpp> 
#include <boost/shared_ptr.hpp> 
#include <string> 

class DatabaseUpdateChecker{ 
    public: 
    DatabaseUpdateChecker(boost::asio::io_service& io, const int& sleepTimeSeconds) 
    :timer_(io,boost::posix_time::seconds(sleepTimeSeconds)),sleepSeconds_(sleepTimeSeconds){ 
     this->timer_.async_wait(boost::bind(&DatabaseUpdateChecker::doDBUpdateCheck,this,boost::asio::placeholders::error)); 
    }; 

    protected: 
    void doDBUpdateCheck(const boost::system::error_code& error){ 
     if(!error){ 
      std::cout << " Checking Database for updates" << std::endl; 
      //Reschdule ourself 
      this->timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(this->sleepSeconds_)); 
      this->timer_.async_wait(boost::bind(&DatabaseUpdateChecker::doDBUpdateCheck,this,boost::asio::placeholders::error)); 
     } 
    }; 
    private: 
    boost::asio::deadline_timer timer_; 
    int sleepSeconds_; 
}; 

typedef boost::shared_ptr<boost::asio::ip::tcp::socket> TcpSocketPtr; 

class NetworkRequest{ 
    public: 
    NetworkRequest(boost::asio::io_service& io, const int& port) 
    :acceptor_(io,boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(),port)){ 
     this->start_accept(); 
    }; 
    protected: 
    void start_accept(){ 
     TcpSocketPtr socketPtr(new boost::asio::ip::tcp::socket(acceptor_.get_io_service())); 
     std::cout << "About to accept new connection" << std::endl; 
     acceptor_.async_accept(*socketPtr,boost::bind(&NetworkRequest::handle_accept,this,socketPtr,boost::asio::placeholders::error)); 
    }; 
    void handle_accept(TcpSocketPtr socketPtr,const boost::system::error_code& error){ 
     std::cout << "Accepted new network connection" << std::endl; 
     if(!error){ 
      std::string response("This is a response\n"); 
      boost::asio::async_write(*socketPtr,boost::asio::buffer(response), 
       boost::bind(&NetworkRequest::handle_write,this,boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred)); 
     } 
     //Start listeing for a new connection 
     this->start_accept(); 
    } 
    void handle_write(const boost::system::error_code& error,size_t size){ 
     if(!error){ 
      std::cout << "Wrote out " << size << " bytes to the network connection" << std::endl; 
     } 

    } 
    private: 
    boost::asio::ip::tcp::acceptor acceptor_; 
}; 

int main(int argc, char *argv[]) { 
    static const int DB_TIMER_SECONDS=5; 
    static const int LISTENING_TCP_PORT=4444; 

    std::cout << "About to start" << std::endl; 
    boost::asio::io_service io; 

    DatabaseUpdateChecker dbChecker(io,DB_TIMER_SECONDS); 
    NetworkRequest networkRequestAcceptor(io,LISTENING_TCP_PORT); 

    io.run(); 

    std::cout << "This won't be printed" << std::endl; 
    return 0; 
} 

編譯和運行中,它會顯示數據庫更新檢查程序會檢查是否有更新,每5秒,而上偵聽連接TCP端口4444.要查看代碼接受新的連接,您可以使用telnet/netcat /您最喜愛的網絡客戶端工具....

telnet 127.0.0.1 4444 
Trying 127.0.0.1... 
Connected to localhost. 
Escape character is '^]'. 
This is a response 
Connection closed by foreign host. 

如果您發現更新和/或請求的處理花費的時間顯著量那麼我會考慮將應用程序線程運行在它自己的線程每一個任務。 io_service將安排它必須完成的工作,並在沒有更多工作前完成。訣竅是讓這些正在做的工作在完成後重新安排。

當然你必須考慮別人對你的問題的評論。我不知道CORBA接口如何可能會使這個複雜化,但我認爲boost :: asio作爲一個異步C++庫將是一個很好的決定,並且足夠靈活用於描述你所描述的內容。

1

這聽起來像是,當系統連續處理網絡請求時,它與數據庫異步通信。

這意味着當它需要與數據庫交談時,它會發送一個查詢,但不會等待響應。

當它從DB獲得響應時,它會處理它。

異步部分可以通過一個單獨的線程與DB進行通信來實現,當它獲得響應時,它會在服務器隊列中發送一個處理請求。

或者服務器可能在多個套接字上偵聽數據,其中一個可能是數據庫連接,它從數據庫獲取響應。

1

所以基本上(如果我正確理解你的話),你需要定期輪詢一個數據庫,看看它是否發生了變化。而當它發生變化時,您需要通知基於CORBA的請求處理器已經發生變化。

我會做的是添加一個新的請求類型到您的CORBA服務器。請求將是「數據庫已更新。」。然後,您可以編寫一個小的,完全不同的程序,只需要在數據庫更新時輪詢數據庫併發送CORBA請求。

這樣,您可以將數據庫更新消息摺疊到CORBA服務器的主要請求流中。

沒有線程,沒有異步任何東西。只有兩個進程都在做自己的事情。