2010-11-09 173 views
4

我有一個像這樣定義的類:這不是全部完成,可能不會編譯。內部類和初始化

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

我的問題是,我如何初始化傳入名爲服務器的外部類中的工人數組。

我想要的是工作線程的向量。每個工作線程都有自己的狀態,但可以訪問其他一些共享數據(未顯示)。另外,我如何創建線程。它們應該在第一次創建類對象時創建,還是從thread_group的外部創建。

另外,我該如何幹淨而安全地關閉線程?

編輯:

看來,我可以這樣初始化工作人員:

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

而且目前我在做這在服務器::運行以創建線程。

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

有沒有人看到這個問題? 安全關機如何?

編輯: 我發現它的一個問題是,工人對象似乎並不構建! oops。是的,他們確實需要Worker類的複製構造函數。

但奇怪的是,創建線程會導致多次調用Worker的複製構造函數。

+0

輸入隊列從哪裏來?你想創造多少工人? – 2010-11-09 10:15:46

+0

我已經刪除了輸入隊列。我認爲它會讓事情混淆。如果我想創建的工作人員數量是可變的並且來自配置文件。 – Matt 2010-11-09 10:20:12

+0

你真的需要在另一個類中定義一個類嗎?它只會讓我對它不那麼可讀。 – 2010-11-09 10:25:47

回答

0

你看過boost asio嗎?它看起來可能很適合你想要做的事情。另外,你可以從許多線程調用boost asio的io_service的運行(類似於你的Run方法),即你可以在很多線程中處理你的IO。基於asio的線程池也可能是http://think-async.com/Asio/Recipes

看看asio的例子。也許他們提供了另一種處理你想要做的事情的方法。 ESP。看看如何完成乾淨的關閉。

+0

是的,它實際上使用ASIO! – Matt 2010-11-09 11:05:41

1

我與純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; 
} 

沒有同步碼在這裏,因爲我沒有時間enougth做到這一點......但我希望它會幫助你=)

+0

對於同步,您可以使用(例如)關鍵部分 – 2010-11-10 08:00:15