2010-11-09 109 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