Chinaunix首页 | 论坛 | 博客
  • 博客访问: 141718
  • 博文数量: 10
  • 博客积分: 2431
  • 博客等级: 大尉
  • 技术积分: 266
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-02 00:56
文章分类
文章存档

2016年(1)

2013年(2)

2011年(3)

2010年(4)

分类: C/C++

2010-11-16 19:31:04

        Windows的"线程池"不仅仅是个线程管理的池子。它有很多高级作用。
1:以异步方式调用函数
2:每隔一段时间调用一个函数
3:在内核对象触发时调用一个函数
4:在异步I/O请求完成时调用一个函数
        第一个方式,显然就是普通的"线程池"都能做到的事情。用QueueUserWorkItem函数替代CreateThread来创建一个新的线程(例如socket监听返回一个客户端的连接)。
        第二个方式,是计时器的作用。Windows GUI的计时器是和HWND绑定的,一次声明一个计时器,计时器结束的时候需要重新设定,用起来麻烦,而且是和消息队列绑定,无法用于复杂的后台服务。Windows线程池则解决了这个问题。
        第三个方式,类似于Overlapped IO和线程同步编程。当然,线程同步的一堆复杂问题,已经由线程池为我们解决了,不再需要头疼了。
        第四个方式,类似于AIO(APC),我们不再需要为每个I/O操作去指定Completion的回调操作,而是将这个回调注册给线程池统一管理。

        第一个方式不用再举例,第四个方式要放在IOCP里面阐述。本文只讨论二,三两种方式。
        第二个方式显然可以用于某种时间触发----下面这个例子声明了两个定时器,一个1s,一个2.5s。和直接用Sleep有什么不同呢? Sleep不管之前之后消耗了多少时间,都Sleep一个固定的区间,而Timer则是在精确的时间点唤醒回调函数,不受系统负载和程序cpu占用情况的影响。

#include "stdafx.h"
#include<windows.h>
#include<stdio.h>
int count=0;
HANDLE hEvent,tq,timer1,timer2;
void __stdcall f1(PVOID,BOOL){
    printf("计时器1: 1s %d\n",++count);
    if(count>20)SetEvent(hEvent);
}
void __stdcall f2(PVOID,BOOL){
    printf("计时器2: 2.5s %d\n",++count);
    if(count>20)SetEvent(hEvent);
}
int _tmain(int argc, _TCHAR* argv[])
{
    if(NULL==(hEvent=CreateEvent(NULL,FALSE,FALSE,"myevent"))){
        printf("CreateEvent失败:%d\n",GetLastError());
        return 1;
    }
    ResetEvent(hEvent);
    if(NULL==(tq=CreateTimerQueue())){
        printf("CreateTimerQueue失败:%d\n",GetLastError());
        return 1;
    }
    if(!(CreateTimerQueueTimer(&timer1,tq,(WAITORTIMERCALLBACK)f1,0,1000,1000,0)
     &&CreateTimerQueueTimer(&timer2,tq,(WAITORTIMERCALLBACK)f2,0,2500,2500,0))){
         printf("CreateTimerQueueTimer失败:%d\n",GetLastError());
         return 1;
    }
    printf("开始计时\n");
    WaitForSingleObject(hEvent,INFINITE);
    DeleteTimerQueueTimer(tq,timer1,INVALID_HANDLE_VALUE);
    DeleteTimerQueueTimer(tq,timer2,INVALID_HANDLE_VALUE);
    DeleteTimerQueueEx(tq,INVALID_HANDLE_VALUE);
    return 0;
}

程序运行输出:
开始计时
计时器1: 1s 1
计时器1: 1s 2
计时器2: 2.5s 3
计时器1: 1s 4
计时器1: 1s 5
计时器2: 2.5s 6
计时器1: 1s 7
计时器1: 1s 8
计时器1: 1s 9
计时器2: 2.5s 10
计时器1: 1s 11
计时器1: 1s 12
计时器1: 1s 13
计时器2: 2.5s 14
计时器1: 1s 15
计时器1: 1s 16
计时器2: 2.5s 17
计时器1: 1s 18
计时器1: 1s 19
计时器1: 1s 20
计时器2: 2.5s 21
Press any key to continue . . .


        第三种情况,可以在上面的程序基础上改,把SetEvent的事件对象计数器,放到线程池里面去,让RegisterWaitForSingleObject来处理:

#include "stdafx.h"
#include<windows.h>
#include<stdio.h>
int count=0;
HANDLE hEvent,tq,timer1,hWait;
void __stdcall f(PVOID,BOOL){
    printf("计时器1: 1s %d\n",++count);
}
void __stdcall reg(PVOID pParam,BOOL){
    HANDLE hEvent=*(HANDLE*)(pParam);
    SetEvent(hEvent);
}
int _tmain(int argc, _TCHAR* argv[])
{
    if(NULL==(hEvent=CreateEvent(NULL,FALSE,FALSE,"myevent"))){
        printf("CreateEvent失败:%d\n",GetLastError());
        return 1;
    }
    ResetEvent(hEvent);
    if(NULL==(tq=CreateTimerQueue())){
        printf("CreateTimerQueue失败:%d\n",GetLastError());
        return 1;
    }
    if(!CreateTimerQueueTimer(&timer1,tq,(WAITORTIMERCALLBACK)f,0,1000,1000,0)){
         printf("CreateTimerQueueTimer失败:%d\n",GetLastError());
         return 1;
    }
    printf("开始计时\n");
    RegisterWaitForSingleObject(&hWait,hEvent,(WAITORTIMERCALLBACK)reg,&hEvent,4000,0);
    WaitForSingleObject(hEvent,INFINITE);
    DeleteTimerQueueTimer(tq,timer1,INVALID_HANDLE_VALUE);
    DeleteTimerQueueEx(tq,INVALID_HANDLE_VALUE);
    return 0;
}

        程序输出是:
开始计时
计时器1: 1s 1
计时器1: 1s 2
计时器1: 1s 3
计时器1: 1s 4
Press any key to continue . . .
Windows编程 什么是作业
Windows编程 一个最简单的打印程序
Unix和Windows高级编程: 共享IO/异步IO
Windows编程 线程池的具体作用
Windows编程 AIO,APC,IOCP
阅读(4113) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~