5

A Server which will run forever and processes requests needs an asynchronous part of code in it which will execute some database queries and update only when there are any new changes to it. The server has to run forever and this function for executing a db function again and again has to run asynchronously, so that there is not hindrance the server because of update once in every 'x' minutes.

How best this can be processed asynchronously in c++ ? How can I set that function alone to run on a daemon so that it doesn't block the server at all ?

NmdMystery
  • 2,778
  • 3
  • 32
  • 60
King
  • 1,170
  • 2
  • 16
  • 33
  • How about a multi-threaded program? – Kerrek SB Dec 15 '11 at 23:14
  • 6
    Have you checked out Boost ASIO? There are synchronous and asynchronous IO, timers, and more. http://www.boost.org/doc/libs/release/libs/asio/ – Joel Dec 15 '11 at 23:17
  • To use a threaded approach. Can I set that thread to daemon like how its done in python? Because rest of the program really doesn't need threads as its over CORBA. @Joel coming to ASIO, please enlighten me. It looks like a good option(I have very little knowledge of asio) but there seems to a blocking call to io_service.run(). I want to asynchronously run the function for dbqueries periodically no matter what the server does. They are pretty much detached except they are going to share a variable. While the server continues to run , the other function has to run asynchronously. – King Dec 15 '11 at 23:58
  • Yes, a thread can be set as a 'detached' thread, though it may not really matter if it is or not. @Joel: Boost ASIO is going to be really difficult to use when he has to make it somehow interface with a CORBA library (a huge, ungainly beast), and a DB access library (another beast, and often very opaque). – Omnifarious Dec 16 '11 at 01:40
  • 1
    Boost ASIO works by providing callback functions when an asynchronous event occurs. You schedule the events to run in an io_service so you so block in a call to run() until there is no work to do. This works well for daemons though as you'll always be listening for new requests so there will always be some work scheduled in the io_service. @Omnifarious, I can't speak to the pains of the CORBA interface and Boost ASIO looks intimidating at first but once you go through the tutorials/examples you find it isn't as daunting as you thought. – Joel Dec 16 '11 at 14:41
  • @Joel: I've used Boost ASIO. It's nice, but I still think is significantly more complex than what is needed for what the OP wants. – Omnifarious Dec 16 '11 at 19:14

3 Answers3

5

I'd strongly recommend using Boost's ASIO library

You'd need a class to accept new requests and another to periodically check for updates. Both could do their work asynchronously and use the same boost::asio::io_service to schedule work.

The setup would be

  • A network asynchronous boost::asio::ip::tcp::acceptor listening for new requests.
  • A boost::asio::deadline_time do an asynchronous wait do check for updates to the database.

Pseudo code for what I understand you are describing is below:

#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;
}

Compiling the above and running it will show that the Database Update Checker will check for updates every 5 seconds while listening for connections on TCP port 4444. To see the code accept a new connection you can use telnet/netcat/your favorite network client tool....

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.

If you find that the processing of updates and/or requests takes a significant amount of time then I'd look into threading your application and running each task in it's own thread. io_service will schedule what work it has to do and not complete until there is no more work. The trick is to have the classes doing work reschedule themselves when they are done.

Of course you have to take into account the comments of others on your question. I dont' know how a CORBA interface might complicate this but I would think boost::asio as an asynchronous C++ library would be a good decision and flexible enough for what you describe.

Joel
  • 2,928
  • 2
  • 24
  • 34
  • I ended up using boost asio.Infact the deadline timer as you have used. took a while to appreciate it. Everything went behind the CORBA. So it doesn't matter. the asynchronous part of the program works its way aside while server processes requests. Thanks ! You are the one of the people who convinced me yesterday ! Works a charm ! boost::asio has a powerful capability of handling of tons of requests which I was very skeptic about. – King Dec 17 '11 at 01:32
1

It sounds like what it means is that while the system processes network requests continuously it asynchronously communicates with the DB.

What it means is that when it needs to talk to DB it sends a query but does not wait for response.

When it gets response from DB it processes it.

The asynchronous part could be implemented by having a separate thread that talks to DB and when it gets response it posts an even in the server queue for processing.

Or the server could be listening on many sockets for data and one of them could be a database connection where it gets responses from DB.

stefanB
  • 77,323
  • 27
  • 116
  • 141
  • Server doesn't send queries. Rather I cache the table as it is very limited data. The function which I want to make it asynchronous does the caching. So, while caching happens asynchronously, the server continues. – King Dec 16 '11 at 00:07
1

So basically (if I understand you correctly) you need to poll a database periodically to see if it's changed. And when it has changed, you need to notify a CORBA-based request processor that there has been a change.

What I would do is add a new request type to your CORBA server. The request would be "The database has updated.". Then you can write a small, completely different program who's only job is to poll the database and send the CORBA request when the database has been updated.

That way, you can fold the database update message into the main request stream for the CORBA server.

No threads, no asynchronous anything. Just two processes each doing their own thing.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194
  • Polling a database frequently and passing between each other would be blocking and a little waste of time. Every milli second is precious in real-time. Though I implemented the thing asynchronously. To update, I'm going to poll the db to see if there are really any changes. – King Dec 17 '11 at 01:52
  • @Dumb: Then I don't understand what you were asking. How do you figure out if the database table has changed without polling it frequently? – Omnifarious Dec 17 '11 at 02:18
  • Ofcourse true that we have to poll the db !. You are spot on. But I wanted to know if I can put everything behind an asynchronous wrapper. Running it on a separate process which will again interact with each other over CORBA gives me little lag there in time. – King Dec 17 '11 at 12:50
  • @Dumb: How is the thread that polls the DB interacting with the thread running your CORBA server? – Omnifarious Dec 17 '11 at 18:47
  • The thread is spawned from the server when it sets itself up . So while the entire set up is behind CORBA. the DB stuff happens back-end while CORBA just handles the service and requests on server. Its very easier than said as far as my choice of words go. Thanks. – King Dec 17 '11 at 22:22
  • @Dumb: That wasn't the question I asked. How does the DB polling loop inform the CORBA side that the DB has changed? – Omnifarious Dec 17 '11 at 22:30
  • It notifies from within. Its a part of the server which is going to work async. – King Dec 17 '11 at 23:20
  • 1
    @Dumb: How does it notify? Does it write data into a socket? Does it alter a shared variable that you poll from the server? – Omnifarious Dec 17 '11 at 23:25
  • A shared variable for which I would have a shared pointer and access it from there. – King Dec 17 '11 at 23:30
  • @Dumb: Interesting. Well, I can't see how boost ASIO helped you with that. But that is an implementation technique that requires multiple threads. OK. – Omnifarious Dec 17 '11 at 23:36