Внутренний класс и инициализация - PullRequest
4 голосов
/ 09 ноября 2010

У меня определен класс, подобный следующему: это не все завершено и, вероятно, не будет компилироваться.

class Server
{
public:
  Server();
  ~Server();

  class Worker
  {
  public: 
    Worker(Server& server) : _server(server) { }
    ~Worker() { }

    void Run() { }
    void Stop() { }

  private:  
    Server& _server;
  }


  void Run()
  {
    while(true) {
       // do work
    }
   }

  void Stop()
  {
     // How do I stop the thread?
  }

private:
  std::vector<Worker> _workers;
};

Мой вопрос: как мне инициализировать рабочий массив, передаваемый во внешний класс с именем Server.

То, что я хочу, это вектор рабочих потоков.Каждый рабочий поток имеет свое собственное состояние, но может получить доступ к некоторым другим общим данным (не показано).Также как мне создавать темы.Должны ли они быть созданы при первом создании объекта класса или извне из группы нитей.

Кроме того, как мне выполнить чистое и безопасное завершение потоков?1011 * Кажется, что я могу инициализировать Worker следующим образом:

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

И сейчас я делаю это в Server :: Run для создания потоков.

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

Кто-нибудь видиткакие-то проблемы с этим?А как насчет безопасного отключения?

РЕДАКТИРОВАТЬ: Одна проблема, которую я обнаружил с этим, заключается в том, что объекты Worker, кажется, не создаются!упс.Да, мне нужен конструктор копирования в классе Worker.

Но, как ни странно, создание потоков приводит к тому, что конструктор копирования для Worker вызывается несколько раз.

Ответы [ 2 ]

1 голос
/ 10 ноября 2010

Я сделал это с чистым WINAPI, посмотрите:

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

Здесь нет кода синхронизации, потому что у меня нет времени, чтобы сделать это ... Но я бы хотел, чтобы это помогло вам =)

0 голосов
/ 09 ноября 2010

Вы смотрели на boost asio вообще? Похоже, это может быть хорошо подходит для того, что вы пытаетесь сделать. Кроме того, вы можете вызывать run io_service boost asio (аналогично вашему методу Run) из многих потоков, то есть вы можете обрабатывать IO во многих потоках. Также может представлять интерес http://think -async.com / Asio / Recipes для пула потоков на основе asio.

Посмотрите на примеры asio. Возможно, они предлагают альтернативный способ обработки того, что вы пытаетесь сделать. Особенно посмотрите, как завершается чистое отключение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...