2010-11-09 6 views
4

J'ai une classe définie comme ceci: Ceci n'est pas complet et ne compilera probablement pas. Ma question est, comment est-ce que j'initialise le tableau de travailleurs passant dans la classe externe nommée Server.Classe interne et initialisation

Ce que je veux est un vecteur de threads de travail. Chaque thread de travail a son propre état mais peut accéder à d'autres données partagées (non affichées). Aussi, comment puis-je créer les discussions. Doivent-ils être créés lors de la création de l'objet de classe ou en externe à partir d'un groupe de threads?

De même, comment dois-je procéder pour arrêter les filets de manière propre et sûre?

EDIT:

Il semble que je peux initialiser Worker comme ceci:

Server::Server(int thread_count) 
    : _workers(thread_count), Worker(*this)), _thread_count(thread_count) { } 

Et je suis en train de faire cela dans Run Server pour créer les threads.

boost::thread_group _threads; // a Server member variable 

Server::Run(){ 
    for (int i = 0; i < _thread_count; i++) 
    _threads.create_thread(boost::bind(&Server::Worker::Run, _workers(i))); 

    // main thread. 
    while(1) { 
     // Do stuff 
    } 

    _threads.join_all(); 
} 

Quelqu'un a-t-il des problèmes avec cela? Et qu'en est-il de l'arrêt sûr? Un problème que j'ai trouvé avec lui est que les objets de travail ne semblent pas être construits! oups. Oui, ils ont besoin d'un constructeur de copie sur la classe Worker. Mais bizarrement, la création des threads a pour résultat que le constructeur de copie pour Worker est appelé plusieurs fois.

+0

D'où vient la file d'attente d'entrée? Combien de travailleurs voulez-vous créer? –

+0

J'ai supprimé la file d'attente d'entrée. Je pense que cela déroute les choses. Le nombre si les travailleurs que je veux créer est variable et provient d'un fichier de configuration. – Matt

+0

Avez-vous vraiment besoin d'une classe à définir dans l'autre? Cela ne fait que me rendre moins lisible. –

Répondre

0

Avez-vous regardé du tout? Il semble que cela pourrait convenir à ce que vous essayez de faire. De plus, vous pouvez appeler l'exécution de io_service de boost asio (similaire à votre méthode Run) à partir de nombreux threads, c'est-à-dire que vous pouvez traiter votre E/S dans de nombreux threads. Egalement intéressant, http://think-async.com/Asio/Recipes pour un pool d'unités d'exécution basé sur Asio.

Regardez les exemples asio. Peut-être qu'ils offrent une autre façon de gérer ce que vous essayez de faire. Esp. Jetez un coup d'œil à la façon dont une fermeture propre est accomplie.

+0

Oui, il utilise actuellement ASIO! – Matt

1

Je l'ai fait avec WINAPI pur, regardez:

#include <stdio.h> 
#include <conio.h> 
#include <windows.h> 
#include <vector> 

using namespace std; 

class Server 
{ 

public: 

    class Worker 
    { 
     int  m_id; 
     DWORD m_threadId; 
     HANDLE m_threadHandle; 
     bool m_active; 

     friend Server; 

    public: 

     Worker (int id) 
     { 
      m_id = id; 
      m_threadId = 0; 
      m_threadHandle = 0; 
      m_active = true; 
     } 

     static DWORD WINAPI Run (LPVOID lpParam) 
     { 
      Worker* p = (Worker*) lpParam;  // it's needed because of the static modifier 

      while (p->m_active) 
      { 
       printf ("I'm a thread #%i\n", p->m_id); 
       Sleep (1000); 
      } 

      return 0; 
     } 

     void Stop() 
     { 
      m_active = false; 
     } 
    }; 

    Server() 
    { 
     m_workers = new vector <Worker*>(); 
     m_count = 0; 
    } 

    ~Server() 
    { 
     delete m_workers; 
    } 

    void Run() 
    { 
     puts ("Server is run"); 
    } 

    void Stop() 
    { 
     while (m_count > 0) 
      RemoveWorker(); 

     puts ("Server has been stopped"); 
    } 

    void AddWorker() 
    { 
     HANDLE h; 
     DWORD threadId; 

     Worker* n = new Worker (m_count ++); 
     m_workers->push_back (n); 

     h = CreateThread (NULL, 0, Worker::Run, (VOID*) n, CREATE_SUSPENDED, &threadId); 
     n->m_threadHandle = h; 
     n->m_threadId = threadId; 
     ResumeThread (h); 
    } 

    void RemoveWorker() 
    { 
     HANDLE h; 
     DWORD threadId; 

     if (m_count <= 0) 
      return; 

     Worker* n = m_workers->at (m_count - 1); 
     m_workers->pop_back(); 

     n->Stop(); 
     TerminateThread (n->m_threadHandle, 0); 

     m_count --; 

     delete n; 
    } 

private: 

    int     m_count; 
    vector <Worker*>* m_workers; 
}; 

int main (void) 
{ 
    Server a; 
    int  com = 1; 

    a.Run(); 

    while (com) 
    { 
     if (kbhit()) 
     { 
      switch (getch()) 
      { 
      case 27:  // escape key code 

       com = 0; 
       break; 

      case 'a':  // add worker 

       a.AddWorker(); 
       break; 

      case 'r':  // remove worker 

       a.RemoveWorker(); 
       break; 

      } 
     } 
    } 

    a.Stop(); 

    return 0; 
} 

Il pas de code de synchronisation ici, parce que je ne peuvent acceuillir le temps de le faire ... Mais je le veux vous aider =)

+0

Pour la synchronisation, vous pouvez utiliser, par exemple, des sections critiques –