Windows线程池

目录
1、线程池是什么?解决了什么问题?
2、Windows封装的线程池解析
3、自我封装实现的线程池解析

1、线程池是什么?解决了什么问题?

传统线程的工作方式:凡是用过多线程的同学应该明白,一个线程生存周期基本可以分为三部分:线程创建、线程执行(可能还会有线程同步)、线程销毁。对于我们来说,我们创建线程最期待的只是线程执行,对于线程创建与线程销毁我们并不感兴趣,因为他们不仅浪费时间而且不做事,所以一个线程真正做事的比例占 (执行)/(创建+执行+销毁)。
线程池:于是为了避免一个程序需要大量创建线程时的不必要浪费,也就是最好的去避免线程创建与线程销毁的时间浪费,此时线程池就出现了。线程池的实现就是在初始的时候创建一些线程(业界通常认为创建CPU核心数的两倍为最佳,也有说是两倍+1),创建的线程为挂起状态(就绪),当我们有任务要处理的时候,我们就激活一个就绪的线程去完成任务,完成任务后,线程又变为就绪态进行继续等待任务的到来。这样过程使得每个线程一次创建,多次使用,如果你的程序并没有多次任务处理,使得线程池中的线程长时间处于就绪态,此时就建议你直接使用一个线程就好,不必使用线程池。
结合生活说明:假如你是一个工地的小包工头(由于没多少搬砖任务,所以手下没有常工),每次有搬砖任务的时候,你都要去找一个工人(线程)来完成任务,因为工人是临时的而且你没有住处,你还得把人家送回去过夜。但是有一段时间你常有搬砖任务,那就得经常去请人->做事->送回去,忽此时你觉得这样太累了,于是你就思考要不腾个空间(线程池)出来,请几个人常工(线程池中的线程)一直在这里候着,有事就叫他们去做,不用来回跑了。这样节约了路费,没那么浪费时间,但是得长时间腾一个空间给他们住宿。


2、Windows封装的线程池解析

线程池代码示例(Windows自身封装)

#include "stdafx.h"
#include 
#include 
using namespace std;

//线程池的回调函数
VOID WINAPI ThreadPoolCallBack(PTP_CALLBACK_INSTANCE instance, PVOID param)
{
    cout << "param:" << (int)param << "\tThread id = " << GetCurrentThreadId() << endl;
    Sleep(200); // 模拟一个任务时间为100毫秒的执行
    return;
}

DWORD GetNumOfProcess()// 获取CPU的核心数
{
    SYSTEM_INFO sysinfo;
    GetSystemInfo(&sysinfo);                    // 获取操作系统信息
    return sysinfo.dwNumberOfProcessors;
}

int main()
{
    PTP_POOL tPool;
    tPool = CreateThreadpool(NULL);             // 创建一个线程池

    DWORD dwMaxThread = 3;                      // GetNumOfProcess() * 2 + 1;
    //设置线程池参数(线程池中的线程数)
    SetThreadpoolThreadMaximum(tPool, dwMaxThread); // 线程池中最多线程数
    SetThreadpoolThreadMinimum(tPool, 1);       // 线程池中最少线程数

    TP_CALLBACK_ENVIRON tcEnv;
    InitializeThreadpoolEnvironment(&tcEnv);    // 初始化线程池的回调环境
    SetThreadpoolCallbackPool(&tcEnv, tPool);   // 给线程池分配回调环境

    cout << "线程池中的线程数为:" << dwMaxThread << endl << endl;
    //测试例子
    for (int i = 1;i < 20;i++)
    {
        // 向线程池中投递一个任务
        TrySubmitThreadpoolCallback(ThreadPoolCallBack, (PVOID)i, &tcEnv);
    }

    Sleep(100000);
    return 0;
}

他们的使用也就是如此的简单…
本来想解释下代码的,但是思来想去也就这几个API常用,加上代码中的注释也已经足够详细了,也就不一一赘述了。
如果哪天你要使用线程池,再copy去使用就行。
实现的效果:
Windows线程池_第1张图片


3、自我封装实现的线程池解析

鉴于Windows自身封装的已经足够优化了,这里进行自我封装只是方便大家学习,理解其中的思想。
封装实现过程:
Windows线程池_第2张图片
1、初始化指定线程池中线程的数量,然后创建相应数量的线程,此时创建的线程为挂起状态(也就是CreateThread第三个参数为CREATE_SUSPENDED)。然后将线程的信息(包含线程句柄等)保存到一个链表中,方便调度。
2、创建一个用于管理的线程。管理任务队列是否有任务需要处理,如果有任务需要处理,此时就遍历线程池链表中是否有线程是挂起状态,如果有就将任务分配给这个线程并激活(ResumeThread)它,让他去执行。如果没有空闲的线程,就Sleep(50)等待线程处理完任务后再去遍历。
3、如果执行任务的线程完成后,再将它置为挂起状态(SuspendThread),等待有任务到来的时候再激活。


main.cpp

#include 
#include "ThreadPoolManager.h"
using namespace std;

void MyThreadFunc(void* param)
{
    cout << "param = " << (int)param << "\tThread id = " << GetCurrentThreadId() << endl;
    Sleep(300);
}

int main()
{
    CreateMyThreadPool(3);
    for (int i = 1; i < 20; i++)
    {
        PostTaskToPool(MyThreadFunc, (void*)i);
    }
    Sleep(100000);
    return 0;
}

实现效果:
Windows线程池_第3张图片
CreateMyThreadPool(3) // 给线程池创建三个线程
PostTaskToPool(MyThreadFunc, (void*)i) // 将任务放入任务队列中,让线程池中的线程来执行


cThreadPool.h

#pragma once
#include 
#include 
#include 
#include 

typedef void(*ThreadCallBack) (void* param);

enum THD_STATUS//线程状态
{
    running_status,     //被占用状态
    free_status,        //空闲状态
};

struct stThreadInfo//保存每个线程的信息 
{
    HANDLE hHandle;             //句柄
    int id;                     //ID 自定义的
    THD_STATUS status;          //线程状态
    ThreadCallBack func;        //回调函数(自定义的)
    void* param;                //参数
};

struct stThreadExec//保存线程要执行的操作
{
    ThreadCallBack func;
    void* param;
};


class cThreadPool
{
public:
    std::queue m_threadExecQueue;//预执行的线程信息
    std::map<int, stThreadInfo> m_threadInfoMap;
    std::map<int, stThreadInfo>::iterator it;

    HANDLE m_hThreadPMana;

public:
    static cThreadPool* m_threadPool;

    cThreadPool();
    ~cThreadPool();
    cThreadPool(int maxNum);
    cThreadPool(cThreadPool& threadPool){}

    //单例模式
    static cThreadPool* CreateMyThreadPool(int maxNum)
    {
        if (m_threadPool == NULL)
        {
            m_threadPool = new cThreadPool(maxNum);
        }
        return m_threadPool;
    }

    static cThreadPool* GetThreadPool()
    {
        return m_threadPool;
    }

    // 将处理消息加入处理队列中
    void PushMsgToDealQueue(ThreadCallBack func, void* param);

    //检测是否有空余线程,然后取出消息队列中的待处理消息分配给线程,让线程去执行
    void AllocatTask();

    //运行某个线程
    void RunThreadCallback(int id);

    //重置某个线程为空闲状态
    void ResetThread(int id);

    // 清除线程池
    void CleanThreadPool();

    // 处理线程 回调函数 用于处理消息
    static DWORD WINAPI ThreadFunc(void* param);

    // 管理线程 回调函数 用于管理消息队列,然后给处理线程分配队列中的消息
    static DWORD WINAPI CheckExecMsgThread(void* param);
};

cThreadPool.cpp

#include "cThreadPool.h"

cThreadPool* cThreadPool::m_threadPool = NULL;

cThreadPool::cThreadPool()
{
    m_hThreadPMana = 0;
}

cThreadPool::~cThreadPool()
{
    CleanThreadPool();
}

cThreadPool::cThreadPool(int maxNum)
{
    //预先创建一些线程
    for (int i = 1; i <= maxNum; ++i)
    {
        HANDLE hHandle = CreateThread(NULL, 0, ThreadFunc, (void*)i, CREATE_SUSPENDED, NULL);
        stThreadInfo st;
        st.hHandle = hHandle;
        st.id = i;
        st.status = free_status;
        m_threadInfoMap[i] = st;
    }
    //开一个线程不停的遍历是否在队列中有预处理的线程请求
    m_hThreadPMana = CreateThread(NULL, 0, CheckExecMsgThread, NULL, 0, NULL);
}


DWORD WINAPI cThreadPool::ThreadFunc(void* param)
{
    while (true)
    {
        cThreadPool::GetThreadPool()->RunThreadCallback((int)param);
        cThreadPool::GetThreadPool()->ResetThread((int)param);
    }
    return 0;
}


DWORD WINAPI cThreadPool::CheckExecMsgThread(void* param)
{
    while (true)
    {
        cThreadPool::GetThreadPool()->AllocatTask();
        Sleep(50);
    }
    return 0;
}


void cThreadPool::PushMsgToDealQueue(ThreadCallBack func, void* param)
{
    stThreadExec st;
    st.func = func;
    st.param = param;
    m_threadExecQueue.push(st);
}

//检测是否目前有空闲线程,如果有就给任务 分配处理线程
void cThreadPool::AllocatTask()
{
    if (m_threadExecQueue.size() != 0) // 是否有消息处理
    {
        stThreadExec itExec = m_threadExecQueue.front(); //  取出队列最前面的消息
        for (it = m_threadInfoMap.begin(); it != m_threadInfoMap.end(); ++it)
        {
            if ((it->second).status == free_status)
            {
                (it->second).func = itExec.func;
                (it->second).param = itExec.param;
                (it->second).status = running_status;
                ResumeThread((it->second).hHandle);
                m_threadExecQueue.pop(); // 使消息出列
                break;
            }
        }
    }
}

void cThreadPool::RunThreadCallback(int id)
{
    if (m_threadInfoMap[id].status == running_status)
    {
        m_threadInfoMap[id].func(m_threadInfoMap[id].param);
    }
}

void cThreadPool::ResetThread(int id)
{
    m_threadInfoMap[id].status = free_status;
    SuspendThread(m_threadInfoMap[id].hHandle);
}


void cThreadPool::CleanThreadPool()
{
    CloseHandle(m_hThreadPMana);
    for (it = m_threadInfoMap.begin(); it != m_threadInfoMap.end(); ++it)
    {
        CloseHandle((it->second).hHandle);
    }
}

如有不足望多多指正,共同进步
Windows线程池及自我实现的源码:http://pan.baidu.com/s/1qXW6LFu

你可能感兴趣的:(windows)