Chapter11-"windows线程池"之异步调用函数

利用线程池(thread pool)异步调用函数时,不需显式调用 CreateThread 函数,系统会为进程自动创建线程池(thread pool)。线程池的每个线程实际运行你事先定义好的回调函数。

写到这里,也许大多人会想:怎么不直接调用众所周知的 CreateThread 函数去创建线程?这里就有必要讲一下线程池(thread pool)的机制了。

线程池(thread pool)的线程在执行完后不是立即销毁的(CreateThread创建的线程执行完成以后就销毁了),而是再次进入线程池(thread pool),等待进程请求该线程的再次执行。线程池的这种机制使得在需要创建许多线程时,性能会得到较大改善。

线程池利用内部算法能够很好地管理线程,如果线程池的线程有供大于求,它会自动销毁掉部分线程;如果线程供不应求,它会自动创建新线程。(这句话意译于《windows via C/C++》英文版Page340)

线程池的原理:(摘自网络)
来看一下线程池究竟是怎么一回事?其实线程池的原理很简单,类似于操作系统中的缓冲区的概念,它的流程如下:先启动若干数量的线程,并让这些线程都处于睡眠状态,当客户端有一个新请求时,就会唤醒线程池中的某一个睡眠线程,让它来处理客户端的这个请求,当处理完这个请求后,线程又处于睡眠状态。可能你也许会问:为什么要搞得这么麻烦,如果每当客户端有新的请求时,我就创建一个新的线程不就完了?这也许是个不错的方法,因为它能使得你编写代码相对容易一些,但你却忽略了一个重要的问题??性能!就拿我所在的单位来说,我的单位是一个省级数据大集中的银行网络中心,高峰期每秒的客户端请求并发数超过100,如果为每个客户端请求创建一个新线程的话,那耗费的CPU时间和内存将是惊人的,如果采用一个拥有200个线程的线程池,那将会节约大量的的系统资源,使得更多的CPU时间和内存用来处理实际的商业应用,而不是频繁的线程创建与销毁。

线程池异步调用回调函数五步

  1. 自定义线程回调函数,注意回调函数(WorkCallback)的函数原型如下:
    VOID CALLBACK WorkCallback(
      _Inout_      PTP_CALLBACK_INSTANCE Instance,
      _Inout_opt_  PVOID Context,
      _Inout_      PTP_WORK Work
    );
  2. 调用CreateThreadpoolWork 函数创建对应的工作项(PTP_WORK)
    PTP_WORK WINAPI CreateThreadpoolWork(
      _In_         PTP_WORK_CALLBACK pfnwk,  //上面的WorkCallback函数的地址
      _Inout_opt_  PVOID pv,  //传递给WorkCallback函数的参数值,对应WorkCallback参数中的Context参数
      _In_opt_     PTP_CALLBACK_ENVIRON pcbe //WorkCallback运行的环境,如果为空,则表示是默认环境。
    );
    
  3. 调用SubmitThreadpoolWork 函数激活由 CreateThreadpoolWork 函数创建的 PTP_WORK
    VOID WINAPI SubmitThreadpoolWork(
      _Inout_  PTP_WORK pwk  //工作项(PTP_WORK)
    );
    
  4. 调用 WaitForThreadpoolWorkCallbacks 函数,等待线程返回。
  5. 最后执行完任务后,调用CloseThreadpoolWork函数关闭线程池,释放资源
为了测试线程池相对于一般的 CreateThread 函数到底有何优势,用了下面的代码进行测试。在本机(CPU: I5; Momery: 4G)上测试,当频繁使用线程的情况下,线程池又快又好又稳定。
  • 使用线程池,大概跑了9.24s,系统CPU使用率稳定在40%以内(系统还运行了其他程序)。
  • 使用CreateThread,大概跑了11.5s,系统CPU使用率先是上升到78%,后再降至56%(测试环境同上)。
#include <windows.h> 
#include <tchar.h> 
#include <stdio.h> 
#include <time.h>


#define NUM_WORK_ITEM 64
#define NUM_LOOPS (1000)


volatile LONG g_nCurrentTask = 0; 


void NTAPI SimpleCallBack(PTP_CALLBACK_INSTANCE Instance, PVOID pvContext, PTP_WORK Work) 
{ 
  LONG currentTask = InterlockedIncrement(&g_nCurrentTask); 


  printf("[%5d] thread #%2d starts.\n", GetCurrentThreadId(), currentTask); 


  printf("[%5d] thread #%2d ends.\n", GetCurrentThreadId(), currentTask); 


} 


DWORD WINAPI ThreadProc(
            _In_ LPVOID lpParameter
            )
{
  LONG currentTask = InterlockedIncrement(&g_nCurrentTask); 


  printf("[%5d] thread #%2d starts.\n", GetCurrentThreadId(), currentTask); 


  printf("[%5d] thread #%2d ends.\n", GetCurrentThreadId(), currentTask); 


  return 0;
}


void testInThreadpool()
{
  PTP_WORK workItem; 
  clock_t start, end;
  start = clock();


  workItem = CreateThreadpoolWork(SimpleCallBack, NULL, NULL); 


  for (int j = 0; j < NUM_LOOPS; j++)
  {
    for (int i = 0; i < NUM_WORK_ITEM; i++) 
    { 
      SubmitThreadpoolWork(workItem);
    } 


    WaitForThreadpoolWorkCallbacks(workItem, FALSE);
  }


  CloseThreadpoolWork(workItem); 


  end = clock();
  printf("%15s function run time: %fs.\n"
    , __FUNCTION__
    , (double)(end - start) / CLOCKS_PER_SEC);
}


void testInThreads()
{
  HANDLE hThread[NUM_WORK_ITEM];


  clock_t start, end;
  start = clock();
  for (int j = 0; j < NUM_LOOPS; j++)
  {
    for (int i = 0; i < NUM_WORK_ITEM; i++)
    {
      hThread[i] = CreateThread(NULL, NULL, ThreadProc, NULL, 0, NULL);
    }
    WaitForMultipleObjects(NUM_WORK_ITEM, hThread, TRUE, INFINITE);
    for (int i = 0; i < NUM_WORK_ITEM; i++)
    {
      CloseHandle(hThread[i]);
    }
  }


  end = clock();
  printf("%15s function run time: %fs.\n"
    , __FUNCTION__
    , (double)(end - start) / CLOCKS_PER_SEC);
}


void main() 
{ 
  //testInThreadpool();
  testInThreads();
  printf("done!\n"); 
  getchar();  
} 

《windows核心编程》(笔记)系列文章是本人看《windows核心编程》时的一些学习笔记,有疏忽之处,欢迎各位网友指正。QQ邮箱:job.zhanghui@qq.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值