2011-12-15 8 views
5

Un serveur qui se déroulera à jamais et traite les demandes a besoin d'une partie asynchrone du code dans ce qui va exécuter des requêtes de base de données et mettre à jour seulement quand il y a des nouvelles modifications. Le serveur doit fonctionner pour toujours et cette fonction pour exécuter une fonction db doit encore et encore fonctionner de manière asynchrone, de sorte qu'il n'y ait pas d'encombrement du serveur à cause d'une mise à jour une fois par 'x' minutes.traitement asynchrone en C++

Comment cela peut-il être traité de manière asynchrone en C++? Comment puis-je définir cette fonction seule pour qu'elle s'exécute sur un démon afin qu'elle ne bloque pas le serveur?

+0

Que diriez-vous d'un programme multi-thread? –

+6

Avez-vous vérifié Boost ASIO? Il y a des E/S synchrones et asynchrones, des temporisations, et plus encore. http://www.boost.org/doc/libs/release/libs/asio/ – Joel

+0

Pour utiliser une approche filetée. Puis-je définir ce thread sur démon comme comment c'est fait en python? Parce que le reste du programme n'a pas besoin de threads comme CORBA. @Joel venir à l'ASIO, s'il vous plaît éclairez-moi. Cela ressemble à une bonne option (j'ai très peu de connaissance d'asio) mais il semble y avoir un appel bloquant à io_service.run(). Je veux exécuter de manière asynchrone la fonction pour dbqueries périodiquement, peu importe ce que le serveur fait. Ils sont plutôt détachés, sauf qu'ils vont partager une variable. Pendant que le serveur continue à fonctionner, l'autre fonction doit s'exécuter de manière asynchrone. – King

Répondre

5

Je vous recommande fortement d'utiliser Boost's bibliothèque ASIO

Vous auriez besoin d'une classe d'accepter de nouvelles demandes et une autre pour vérifier périodiquement les mises à jour. Les deux peuvent faire leur travail de manière asynchrone et utiliser le même boost :: asio :: io_service pour planifier le travail.

La configuration serait

  • Un réseau asynchrone boost::asio::ip::tcp::acceptor l'écoute de nouvelles demandes.
  • A boost::asio::deadline_time faire une attente asynchrone vérifie les mises à jour de la base de données.

Pseudo code pour ce que je comprends que vous décrivez est ci-dessous:

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

Compiler ce qui précède et en cours d'exécution, il montrera que la base de données mise à jour Checker vérifiera les mises à jour toutes les 5 secondes pendant l'écoute des connexions sur Port TCP 4444. Pour voir le code accepter une nouvelle connexion, vous pouvez utiliser telnet/netcat/votre outil client réseau favori ....

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. 

Si vous trouvez que le traitement des mises à jour et/ou des demandes prend beaucoup de temps alors je regarderais en enfilant votre application et l'exécution de chaque tâche dans son propre fil. io_service va programmer ce qu'il doit faire et ne pas terminer jusqu'à ce qu'il n'y ait plus de travail. L'astuce consiste à faire redéployer les classes lorsqu'elles sont terminées.

Bien sûr, vous devez prendre en compte les commentaires des autres sur votre question. Je ne sais pas comment une interface CORBA pourrait compliquer cela, mais je pense que boost :: asio comme une bibliothèque C++ asynchrone serait une bonne décision et assez flexible pour ce que vous décrivez.

+0

J'ai fini par utiliser boost asio.Infact le délai d'expiration que vous avez utilisé. pris un moment pour l'apprécier. Tout est allé derrière le CORBA. Donc ça n'a pas d'importance. la partie asynchrone du programme s'écarte pendant que le serveur traite les demandes. Merci ! Tu es celui des personnes qui m'ont convaincu hier! Fonctionne un charme! boost :: asio a une puissante capacité de traitement de tonnes de requêtes dont j'étais très sceptique. – King

1

Il ressemble à ce que cela signifie est que si le système traite les demandes de réseau en continu, il communique avec le DB de manière asynchrone.

Ce que cela signifie est que quand il a besoin de parler à DB, il envoie une requête mais n'attend pas la réponse.

Lorsqu'il reçoit une réponse de DB, il le traite.

La partie asynchrone peut être mis en oeuvre en ayant un fil séparé qui parle DB et quand il fait suite il affiche une même dans la file d'attente du serveur pour le traitement.

Ou le serveur pourrait être à l'écoute sur de nombreuses prises pour les données et l'un d'entre eux pourrait être une connexion de base de données où il obtient des réponses de DB.

+0

Le serveur n'envoie pas de requêtes. Plutôt je cache la table car c'est des données très limitées. La fonction que je veux rendre asynchrone fait la mise en cache. Ainsi, alors que la mise en cache se produit de manière asynchrone, le serveur continue. – King

1

Donc, en gros (si je comprends bien), vous devez interroger une base de données périodiquement pour voir si elle a changé. Et quand il a changé, vous devez informer un processeur de requêtes basé sur CORBA qu'il y a eu un changement.

Ce que je ferais, c'est d'ajouter un nouveau type de requête à votre serveur CORBA. La requête serait "La base de données a été mise à jour". Ensuite, vous pouvez écrire un petit programme complètement différent dont le seul travail est d'interroger la base de données et d'envoyer la requête CORBA lorsque la base de données a été mise à jour. De cette façon, vous pouvez replier le message de mise à jour de la base de données dans le flux de requêtes principal pour le serveur CORBA.

Aucun fil, rien d'asynchrone. Juste deux processus chacun faisant leur propre chose.

+0

Interroger fréquemment une base de données et passer entre les deux serait un blocage et une perte de temps. Chaque milliseconde est précieuse en temps réel. Bien que j'ai implémenté la chose de manière asynchrone. Pour mettre à jour, je vais interroger le db pour voir s'il y a vraiment des changements. – King

+0

@Dumb: Alors je ne comprends pas ce que vous demandiez. Comment déterminez-vous si la table de base de données a changé sans interroger fréquemment? – Omnifarious

+0

Bien sûr que nous devons interroger le db! Vous êtes sur. Mais je voulais savoir si je pouvais tout mettre derrière un wrapper asynchrone. L'exécuter sur un processus séparé qui va à nouveau interagir les uns avec les autres sur CORBA me donne un petit décalage dans le temps. – King