Windows系统线程池

认识Windows系统线程池可以参考这篇:

https://baike.baidu.com/item/%E7%BA%BF%E7%A8%8B%E6%B1%A0/4745661

 

需要强调的是下面这句:

         调用QueueUserWorkItem时传入的Object类型参数传递到任务过程,可以通过这种方式来向任务过程传递参数:

如果任务过程需要多个参数,可以定义包含这些数据的类,并将其强制转换为Object数据类型

 

在MS提供的Windows Service的C++例程中,提供了一个类,就是使用这种方式(定义一个工作者类)来传递多个线程参数

这个类的定义如下:

class CThreadPool
{
public:

    template
    static void QueueUserWorkItem(void (T::*function)(void),    T *object, ULONG flags = WT_EXECUTELONGFUNCTION/*告诉操作系统工作项目需要长时间的工作*/)
    {

        //std::pair主要的作用是将两个数据组合成一个数据,两个数据可以是同一类型或者不同类型。
        //std::pair实质上是一个结构体,其主要的两个成员变量是first和second,这两个变量可以直接作为成员变量来使用

        typedef std::pair CallbackType;
       
      
 //auto_ptr在构造时获取对某个对象的所有权,在析构时释放该对象
        std::auto_ptr p(new CallbackType(function, object)); 

        /******************************************************************************************************************
            WT_EXECUTEDEFAULT                :工作项目放入非I/O组件得线程中。
            WT_EXECUTEINIOTHREAD            :工作项目放入I/O组件的线程中,这样的线程在I/O请求没有完成之前不会被终止运行,防止因为线程被终止导致I/O请求丢失。
            WT_EXECUTEINPERSISTENTTHREAD    :放入永久线程池。
            WT_EXECUTELONGFUNCTION             :工作项目需要长时间的工作,系统会据此安排更多的线程。
        *************************************************************************************************************************/

        if (::QueueUserWorkItem(ThreadProc, p.get()/*get用来显式的返回auto_ptr所拥有的对象指针*/, flags))
        {
    //下面这句, 智能指针p释放掉对"new CallbackType(function, object)"指针的所有权。
            //这样智能指针析构函数就不会delete 掉"new CallbackType(function, object)"分配的指针了, 工作线程会完成这个释放。

             p.release();
        }
        else
        {
            throw GetLastError();
        }
    }

private:

    template
    static DWORD WINAPI ThreadProc(PVOID context)
    {
        typedef std::pair CallbackType;
 
  
     //p析构函数会自动释放QueueUserWorkItem静态函数中分配的指针
        //auto_ptr析构的时候肯定会删除他所拥有的那个对象,所以我们就要注意了,一个萝卜一个坑,两个auto_ptr不能同时拥有同一个对象。像这样:
        //    int*p = new int(0);
        //    auto_ptrap1(p);
        //    auto_ptrap2(p);
        //    因为ap1与ap2都认为指针p是归它管的,在析构时都试图删除p, 两次删除同一个对象的行为在C++标准中是未定义的。所以我们必须防止这样使用auto_ptr.
        //======================
        //int*pa = new int[10];
        //auto_ptrap(pa);
        //因为auto_ptr的析构函数中删除指针用的是delete, 而不是delete[], 所以我们不应该用auto_ptr来管理一个数组指针。

        std::auto_ptr p(static_cast(context));

        (p->second->*p->first)();
        return 0;
    }
};

 

////// 定义一个工作类,用来帮助进行工作线程参数传递

class CTCPRequsetJob
{
    SOCKET m_socket;
    HWND   m_hWndProcessMsg;

public:
    HWND   m_hWndCmdSource;
    char m_rxbuf[4096];
    int  m_rxdataLen;
    enum { enum_select_error, enum_select_outof_time, enum_server_is_closed, enum_recv_success };

    void  ServiceWorkerThread(void);

    CTCPRequsetJob(SOCKET socket, HWND hWndCmdSource, HWND hWndProcessMsg);
    ~CTCPRequsetJob();
};

CTCPRequsetJob::CTCPRequsetJob(SOCKET socket, HWND hWndCmdSource, HWND hWndProcessMsg) :
m_socket(socket), m_hWndCmdSource(hWndCmdSource), m_hWndProcessMsg(hWndProcessMsg)
{
    m_rxdataLen = 0;
}


CTCPRequsetJob::~CTCPRequsetJob()
{
    
}


void CTCPRequsetJob::ServiceWorkerThread(void)
{
    //使用select方法监控tcp客户端的接入
    int ret = 0;
    timeval tTimeout;
    fd_set sReadSet;

    // Perform main service function here...
    tTimeout.tv_sec = 2;
    tTimeout.tv_usec = 0;

    FD_ZERO(&sReadSet);
    FD_SET(m_socket, &sReadSet);


    ret = select(1, &sReadSet, NULL, NULL, &tTimeout);

    if (ret < 0){
        PostMessage(m_hWndProcessMsg, WM_SOCKET_RESPONSE, (WPARAM)enum_select_error,  (LPARAM)this);
    }
    //
    else if (0 == ret){
        PostMessage(m_hWndProcessMsg, WM_SOCKET_RESPONSE, (WPARAM)enum_select_outof_time, (LPARAM)this);
    }
    //
    else{
            ret = recv(m_socket, m_rxbuf, sizeof(m_rxbuf), 0);
            if (ret <= 0){
                PostMessage(m_hWndProcessMsg, WM_SOCKET_RESPONSE, (WPARAM)enum_server_is_closed, (LPARAM)this);
            }
            else{
                PostMessage(m_hWndProcessMsg, WM_SOCKET_RESPONSE, (WPARAM)enum_recv_success, (LPARAM)this);
                m_rxdataLen = ret;
            }
    }

     //线程结束,销毁这个工作者对象

    delete this;
}

///----工作者线程的创建

        //创建一个工作线程来接收服务端的相应,构造函数入口参数将传递给工作者线程使用
        CTCPRequsetJob*  job = new CTCPRequsetJob(m_socket, hWndRequestSource, GetSafeHwnd());
        CThreadPool::QueueUserWorkItem(&CTCPRequsetJob::ServiceWorkerThread, job);

 

 

 

你可能感兴趣的:(Windows系统线程池)