Win32_Windows线程

一 Windows 线程

  1 Windows线程
    Windows进程中可以执行代码的实体,Windows系统可以调度的执行代码,一个进程中
      至少有一个或多个线程,每个线程是进程的一个任务分支。

  2 线程的特点
    2.1 每个线程有一个ID
    2.2 每个线程有自己的安全属性
    2.3 每个线程有自己的内存栈

  3 进程和线程多任务
    多进程实现的多任务:由于进程地址空间是属于自己私有,内存和资源不能共享。
    多线程实现的多任务:由于线程都是位于同一个进程的地址空间,内存和资源可以共享。

  4 线程的执行
    线程的执行方式采用轮询方式执行。

二 线程的使用

  1 定义线程处理函数

DWORD WINAPI ThreadProc(LPVOID lpParameter);//线程参数

  2 创建线程

HANDLE CreateThread(
  LPSECURITY ATTRIBUTES lpThreadAttributes,//安全属性
  DWORD dwStackSize,//初始化栈的大小,缺省为0
  LPTHREAD_START_ROUTINE lpStartAddress,//线程的函数指针
  LPVOID lpParameter,//线程参数
  DWORD dwCreationFlags,//创建方式
  LPDWORD lpThreadId);//返回线程ID

    返回值是创建好的线程句柄
  3 结束线程
    ExitThread
    TerminateThread
  4 线程挂起和执行
    挂起线程

DWORD SuspendThread(HANDLE hThread);//线程句柄

    执行线程

DWORD ResumeThread(HANDLE hThread);

  5 等候线程的结束
    可以使用 WaitForSingleObject 等候线程的结束

  6 关闭线程序句柄
    CloseHandle

View Code
 1 #include "stdafx.h"
 2 #include "conio.h"
 3 #include "windows.h"
 4 
 5 DWORD WINAPI ThreadProc1(LPVOID pParam)
 6 {
 7     DWORD nValue = (DWORD)pParam;
 8     for(int nIndex = 0;nIndex < 10;nIndex ++)
 9     {
10         printf("Thread Proc1----------%d\n",nValue);
11         Sleep(1000);
12     }
13     return 0;
14 }
15 DWORD WINAPI ThreadProc2(LPVOID pParam)
16 {
17     while(1)
18     {
19         printf("-----------Thread Proc2\n");
20         Sleep(1000);
21     }
22 }
23 void Create()
24 {
25     DWORD nValue = 100;
26     //创建一个挂起的线程
27     DWORD nThreadID = 0;
28     HANDLE hThread =  CreateThread(NULL,0,ThreadProc1,
29         (LPVOID)nValue,CREATE_SUSPENDED,&nThreadID);
30     printf("Thread ID: %d\n",nThreadID);
31     printf("Thread Handle:%p\n",hThread);
32     //执行线程
33     ResumeThread(hThread);
34     //等候线程1结束
35     WaitForSingleObject(hThread,INFINITE);
36     //创建一个立刻执行的线程
37     hThread = CreateThread(NULL,0,ThreadProc2,NULL,0,&nThreadID);
38     printf("Thread 2 ID:%d\n",nThreadID);
39     printf("Thread 2 Handle:%p\n",hThread);
40     //挂起线程
41     //SuspendThread(hThread);
42     CloseHandle(hThread);
43 }
44 
45 int main(int argc, char* argv[])
46 {
47 
48     Create();
49     getch();
50     return 0;
51 }

二 线程局部存储 Thread Local Storage

  1 由于多个线程使用同一个变量,各个线程都对变量进行操作,那么变量的值会被不同线程
    操作覆盖。
   通常   变量  <-- 线程A
             <-- 线程B

   TLS  变量  <-- 线程A
       变量  <-- 线程B

  

View Code
 1 #include "stdafx.h"
 2 #include "conio.h"
 3 #include "stdlib.h"
 4 #include "windows.h"
 5 
 6 CHAR * g_pszText1 = NULL;  //所有子线程共享一个全局变量
 7 //使用关键字定义TLS变量
 8 __declspec(thread) CHAR * g_pszText2 = NULL;
 9 
10 void Print( )
11 {
12     printf( "Text1: %s\n", g_pszText1 );
13     printf( "Text2: %s\n", g_pszText2 );
14 }
15 
16 DWORD WINAPI PrintProc( LPVOID pParam )
17 {
18     CHAR * pszText = (CHAR *)pParam;
19     
20     g_pszText1 = (CHAR *)malloc( 100 );
21     memset( g_pszText1, 0, 100 );
22     strcpy( g_pszText1, pszText );
23 
24     g_pszText2 = (CHAR *)malloc( 100 );
25     memset( g_pszText2, 0, 100 );
26     strcpy( g_pszText2, pszText );
27 
28     while( 1 )
29     {
30         Print( );
31         Sleep( 1000 );
32     }
33     return 0;
34 }
35 
36 void Create( )
37 {
38     DWORD dwThread = 0;
39     CHAR  szText1[] = "Thread 1----------";
40     HANDLE hThread = CreateThread( NULL, 
41         0, PrintProc, szText1, 0, &dwThread );
42 
43     CHAR  szText2[] = "-----Thread 2-----";
44     hThread = CreateThread( NULL, 
45         0, PrintProc, szText2, 0, &dwThread );
46 
47     CHAR  szText3[] = "----------Thread 3";
48     hThread = CreateThread( NULL, 
49         0, PrintProc, szText3, 0, &dwThread );
50 
51     getch( );
52 }
53 
54 int main(int argc, char* argv[])
55 {
56     Create( );
57     return 0;
58 }  


  2 TLS 的使用
    2.1 使用关键字 _declspec(thread)
      _declspec(thread) CHAR* g_pszText2 = NULL
    2.2 TLS 相关API
      2.2.1 创建TLS索引
        DWORD TlsAlloc(VOID)
        返回一个TLS索引号
      2.2.2 设置值

BOOL TlsSetValue(
  DWORD dwTlsIndex,//TLS索引
  LPVOID lpTlsValue);//保存的值

     2.2.3 获取值

LPVOID TlsGetValue(DWORD dwTlsIndex);//TLS索引

       返回存放在索引内的值
    2.2.4 释放

BOOL TlsFree(DWORD dwTlsIndex);//TLS索引
View Code
 1 #include "stdafx.h"
 2 #include "stdlib.h"
 3 #include "windows.h"
 4 
 5 CHAR * g_pszText   = NULL;
 6 DWORD  g_nTlsIndex = 0;
 7 
 8 void Print( )
 9 {
10     printf( "g_pszText: %s\n", g_pszText );
11     //从TLS索引中获取值
12     CHAR * pszText = (CHAR *)
13         TlsGetValue( g_nTlsIndex );
14     printf( "TLS: %s\n", pszText );
15 }
16 
17 DWORD WINAPI PrintProc( LPVOID pParam )
18 {
19     CHAR * pszText = (CHAR *)pParam;
20     g_pszText = (CHAR *)malloc( 100 );
21     strcpy( g_pszText, pszText );
22     //将值保存到TLS索引当中
23     TlsSetValue( g_nTlsIndex, g_pszText );
24 
25     while( 1 )
26     {
27         Print( );
28         Sleep( 1000 );
29     }
30     return 0;
31 }
32 
33 void Create( )
34 {
35     HANDLE hThread   = NULL;
36     DWORD  nThreadID = 0;
37 
38     CHAR szText1[] = "ThreadProc 1----------";
39     hThread = CreateThread( NULL, 0,
40         PrintProc, szText1, 0, &nThreadID );
41 
42     CHAR szText2[] = "-----ThreadProc 2-----";
43     hThread = CreateThread( NULL, 0,
44         PrintProc, szText2, 0, &nThreadID );
45 
46     WaitForSingleObject( hThread, INFINITE );
47 }
48 
49 int main(int argc, char* argv[])
50 {    //创建TLS索引号
51     g_nTlsIndex = TlsAlloc( );
52     //创建线程
53     Create( );
54     //释放索引
55     TlsFree( g_nTlsIndex );
56     return 0;
57 }

三 线程同步

  1 多线程的问题
    A停止 -> B开始 -> B停止 -> A开始
    当线程停止会保存寄存器的状态,当线程开始会恢复寄存器的状态
    AB线程都使用printf
    A线程调用printf时,printf正在输出当中,A挂起,B执行,B线程也调用printf
      输出B的数据,画面会出现A的数据输出1部分,然后是B的数据;B挂起,A
      执行,A继续输出自己的数据。所以由于多线程的切换产生数据混乱。

  2 问题的解决 - 同步机制
    2.1 原子锁
    2.2 临界区
    2.3 事件
    2.4 互斥
    2.5 信号量
    2.6 可等候定时器

  3 等候多个内核对象事件

DWORD WaitForMultipleObjects(
  DWORD nCount,//句柄的数量
  CONST HANDLE *lpHandles,//句柄数组
  BOOL fWaitAll,//等候方式
  DWORD dwMilliseconds);//等候时间

    等候方式fWaitAll:
      TRUE - 等候每个句柄都有事件,解除阻塞
      FALSE - 其中一个句柄有事件解除阻塞

四 原子锁

  1 g_nValue++执行
    线程A通过寄存器完成加法运算,假设g_nValue正在加到10000时,线程切换到
      B,A的寄存器中保存10000数字,B从10000开始加数据,当B加15000时,
      线程切换到A,A恢复寄存器的值A会继续从10000开始累加,就将B完成的5000
      的加法覆盖

   2 原子锁
    执行单个指令时,锁定操作不允许其他线程访问

  3 用法
    InterlockedIncrement ++运算
    InterlockedDecrement --运算
    InterlockedCompareExchange ?运算

View Code
 1 #include "stdafx.h"
 2 #include "windows.h"
 3 
 4 LONG g_nValue1 = 0;
 5 LONG g_nValue2 = 0;
 6 
 7 DWORD WINAPI InterProc1( LPVOID pParam )
 8 {
 9     for( int nIndex=0; nIndex<10000000; nIndex++ )
10     {    
11         g_nValue1++;//普通++
12     }
13     return 0;
14 }
15 DWORD WINAPI InterProc2( LPVOID pParam )
16 {
17     for( int nIndex=0; nIndex<10000000; nIndex++ )
18     {    
19         InterlockedIncrement( &g_nValue2 );//原子锁++(lock)
20     }
21     return 0;
22 }
23 
24 void Create( )
25 {
26     DWORD  nThreadID  = 0;HANDLE hThread[4] = { NULL };
27     hThread[0] = CreateThread( NULL, 0,InterProc1, NULL, 0, &nThreadID );
28     
29     hThread[1] = CreateThread( NULL, 0,InterProc1, NULL, 0, &nThreadID );
30 
31     hThread[2] = CreateThread( NULL, 0,InterProc2, NULL, 0, &nThreadID );
32     
33     hThread[3] = CreateThread( NULL, 0,InterProc2, NULL, 0, &nThreadID );
34 
35     WaitForMultipleObjects( 4, hThread, TRUE, INFINITE );
36 
37     printf( "Value1=%d  Value2=%d\n", 
38         g_nValue1, g_nValue2 );
39 }
40 
41 int main(int argc, char* argv[])
42 {
43     Create( );
44     return 0;
45 }

 

五 临界区

  1 临界区作用
    线程在执行代码时将代码锁定不允许其它线程执行,只有该线程离开后其它才能使用

  2 临界区的使用
    2.1 初始化临界区

VOID InitializeCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection);//临界区结构

    2.2 临界区加锁

VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);//临界区

    2.3 临界区解锁

VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);//临界区

    2.4 释放临界区

VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);//临界区

  3 和原子锁相比
    原子锁是一条语句,临界区可以完成多条语句的锁定

View Code
 1 #include "stdafx.h"
 2 #include "conio.h"
 3 #include "windows.h"
 4 
 5 CRITICAL_SECTION g_cs = {0};
 6 
 7 void Print()
 8 {
 9     EnterCriticalSection(&g_cs);//进入临界区 - 加锁
10     printf("Long long long... ...\n");
11     LeaveCriticalSection(&g_cs);//离开临界区 - 解锁
12 }
13 
14 DWORD WINAPI PrintProc(LPVOID pParam)
15 {
16     while(1)
17     {
18         Print();
19         Sleep(100);
20     }
21     return 0;
22 }
23 
24 void Create()
25 {
26     DWORD nThreadID = 0;
27     HANDLE hThread[2] = {0};
28     hThread[0] = CreateThread(NULL,0,PrintProc,NULL,0,&nThreadID);
29     
30     hThread[1] = CreateThread(NULL,0,PrintProc,NULL,0,&nThreadID);
31 
32     getch();
33 }
34 
35 int main(int argc, char* argv[])
36 {
37     InitializeCriticalSection(&g_cs);//初始化临界区
38     Create();
39     DeleteCriticalSection(&g_cs);//删除临界区
40     return 0;
41 }

 六 事件

  1 事件
    通知的作用,当收到事件时线程可以执行,否则线程将等候事件发生

  2 事件的用法
    2.1 创建事件

HANDLE CreateEvent(
  LPSECURITY_ATTRIBUTES lpEventAttributes,//安全属性
  BOOL bManualReset,//重置方式
  BOOL bInitialState,//初始化状态
  LPCTSTR lpName);

    返回创建好的事件句柄
    bManualReset - 事件重置方式
      TRUE 手动和FALSE自动重置,如果为FALSE,系统在等候到事件后会自动将
       事件重置为无信号状态,如果为TRUE,我们必须自己使用ResetEvent重置状态
      bInitialState - 初始化状态,TRUE为有信号,FALSE 无信号

    2.2 等候事件
      WaitForSingleObject / WaitForMultipleObjects
    2.3 触发事件

BOOL SetEvent(HANDLE hEvent);//事件句柄

    2.4 关闭事件
      CloseHandle
    2.5 重置事件

BOOL ResetEvent(HANDLE hEvent);//事件句柄

    2.6 其它函数
      OpenEvent
      PulseEvent

View Code
 1 #include "stdafx.h"
 2 #include "conio.h"
 3 #include "windows.h"
 4 
 5 HANDLE g_hEvent = NULL;
 6 HANDLE g_hEvent2 = NULL;
 7 
 8 DWORD WINAPI ThreadSend(LPVOID pParam)
 9 {
10     while(1)
11     {
12         //触发事件
13         SetEvent(g_hEvent);
14         Sleep(500);
15         SetEvent(g_hEvent2);
16         Sleep(500);
17     }
18     return 0;
19 }
20 
21 DWORD WINAPI ThreadRecv(LPVOID pParam)
22 {
23     while(1)
24     {
25         WaitForSingleObject(g_hEvent,INFINITE);//等候事件通知
26         printf("Hello Event:%p\n",g_hEvent);
27         ResetEvent(g_hEvent);
28     }
29     return 0;
30 }
31 
32 DWORD WINAPI ThreadRecv2(LPVOID pParam)
33 {
34     while(1)
35     {
36         WaitForSingleObject(g_hEvent2,INFINITE);//等候事件通知
37         printf("Hello Event 2:%p\n",g_hEvent2);
38         ResetEvent(g_hEvent2);
39     }
40     return 0;
41 }
42 
43 void Create()
44 {
45     DWORD nThreadID    = 0;
46     HANDLE hThread[3] = {NULL};
47 
48     hThread[0] = CreateThread(NULL,0,ThreadSend,NULL,0,&nThreadID);
49     hThread[1] = CreateThread(NULL,0,ThreadRecv,NULL,0,&nThreadID);
50     hThread[2] = CreateThread(NULL,0,ThreadRecv2,NULL,0,&nThreadID);
51 }
52 
53 int main(int argc, char* argv[])
54 {
55      g_hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);//创建自动事件
56      g_hEvent2 = CreateEvent(NULL,TRUE,FALSE,NULL);//创建手动重置事件
57     Create();
58     getch();
59     CloseHandle(g_hEvent);//关闭事件
60     return 0;
61 }

 

七 互斥

  1 互斥量
    多个线程同时只能有一个执行

  2 互斥量使用
    2.1 创建互斥

HANDLE CreateMutex(
  LPSECURITY_ATTRIBUTES lpMutexAttributes,//安全属性
  BOOL bInitialOwner,//初始化的拥有线程
  LPCTSTR lpName);//名称

    bInitialOwner - TRUE,表示当前创建互斥量的线程拥有互斥,FALSE为不拥有
    2.2 等候互斥
      WaitForSingleObject
      WaitForMultipleObjects
    2.3 重置互斥
      ReleaseMutex
    2.4 关闭互斥
      CloseHandle
    2.5 使用互斥线程,按照谁先等候谁先拥有互斥量的规则顺序执行
    2.6 其它函数
      OpenMutex 打开互斥

View Code
 1 #include "stdafx.h"
 2 #include "conio.h"
 3 #include "windows.h"
 4 
 5 HANDLE g_hMutex = NULL;
 6 
 7 DWORD WINAPI ThreadProc1(LPVOID pParam)
 8 {
 9     while(1)
10     {
11         WaitForSingleObject(g_hMutex,INFINITE);//等候互斥量
12         printf("ThreadProc1----------\n");
13         Sleep(500);
14         ReleaseMutex(g_hMutex);//释放互斥量
15     }
16     return 0;
17 }
18 DWORD WINAPI ThreadProc2(LPVOID pParam)
19 {
20     while(1)
21     {
22         WaitForSingleObject(g_hMutex,INFINITE);//等候互斥量
23         printf("----------ThreadProc2\n");
24         Sleep(500);
25         ReleaseMutex(g_hMutex);//释放互斥量
26     }
27     return 0;
28 }
29 
30 DWORD WINAPI ThreadProc3(LPVOID pParam)
31 {
32     while(1)
33     {
34         WaitForSingleObject(g_hMutex,INFINITE);//等候互斥量
35         printf("-----ThreadProc3-----\n");
36         Sleep(500);
37         ReleaseMutex(g_hMutex);//释放互斥量
38     }
39     return 0;
40 }
41 
42 void Create()
43 {
44     DWORD nThreadID = 0;
45     HANDLE hThread[3] = {NULL};
46 
47     hThread[0] = CreateThread(NULL,0,ThreadProc1,NULL,0,&nThreadID);
48     hThread[1] = CreateThread(NULL,0,ThreadProc2,NULL,0,&nThreadID);
49     hThread[2] = CreateThread(NULL,0,ThreadProc3,NULL,0,&nThreadID);
50 }
51 
52 int main(int argc, char* argv[])
53 {
54     
55     //创建互斥量
56     g_hMutex = CreateMutex(NULL,FALSE,NULL);
57     Create();
58     getch();
59     CloseHandle(g_hMutex);//关闭
60     return 0;
61 }

 八 信号量

  1 信号量
    通知作用和事件类似,但是与事件不同,事件只维护一个值 0 或 1 ;信号量维护一个变
      量,0 时无信号,大于 0 有信号。

  2 信号量的使用
    2.1 创建信号量

HANDLE CreateSemaphore(
  LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,//安全属性
  LONG lInitialCount,//初始信号量
  LONG lMaximumCount,//最大信号量
  LPCTSTR lpName);//命名

    返回创建好的信号量句柄
    2.2 等候信号量
      WaitForSingleObject
      WaitForMultipleObjects
    2.3 释放信号

BOOL ReleaseSemaphore(
  HANDLE hSemaphore,//信号量句柄
  LONG lReleaseCount,//释放信号的数据
  LPLONG lpPreviousCount);//释放前的数量

    2.4 关闭信号量
      CloseHandle
    2.5 打开信号量
      OpenSemaphore

View Code
 1 #include "stdafx.h"
 2 #include "conio.h"
 3 #include "windows.h"
 4 
 5 HANDLE g_hSemaphore = NULL;
 6 
 7 DWORD WINAPI ThreadSend( LPVOID pParam )
 8 {
 9     while( 1 )
10     {
11         CHAR ch = getch( );
12         switch( ch )
13         {
14         case '1':
15             //释放信号 其实是增加可用空位
16             ReleaseSemaphore( g_hSemaphore,1, NULL );
17             break;
18         case '5':
19             ReleaseSemaphore( g_hSemaphore,5, NULL );
20             break;
21         }
22     }
23     return 0;
24 }
25 
26 DWORD WINAPI ThreadRecv( LPVOID pParam )
27 {
28     while( 1 )
29     {    //等候信号量的信号
30         WaitForSingleObject( g_hSemaphore, INFINITE );
31         printf( "Hello Semaphore\n" );
32         Sleep( 100 );
33     }
34     return 0;
35 }
36 
37 void Create( )
38 {
39     DWORD  nThreadID  = 0;
40     HANDLE hThread[2] = { NULL };
41     hThread[0] = CreateThread( NULL, 0,
42         ThreadSend, NULL, 0, &nThreadID );
43     hThread[1] = CreateThread( NULL, 0,
44         ThreadRecv, NULL, 0, &nThreadID );
45     
46     WaitForMultipleObjects( 2, hThread,
47         TRUE, INFINITE );
48 }
49 
50 int main(int argc, char* argv[])
51 {    //创建信号量
52     g_hSemaphore = CreateSemaphore( 
53         NULL, 3, 10, NULL );  //3表示一开始有3个可用空位
54     Create();
55     //关闭信号量
56     CloseHandle( g_hSemaphore );
57     return 0;
58 }

九 可等候定时器

  1 可等候定时器
    是一个更加精确系统提供的定时器,能够达到100ns级别

  2 定时器的使用
    2.1 创建定时器

HANDLE CreateWaitableTimer(
  LPSECURITY_ATTRIBUTES lpTimerAttributes,//安全属性
  BOOL bManualReset,//重置方式
  LPCTSRT lpTimerName);//命名

    返回创建好的定时器句柄
    2.2 设置定时器

BOOL SetWaitableTimer(
  HANDLE hTimer,//定时器句柄
  const LARGE_INTEGER *pDueTime,//定时器第一次触发时间,100ns级别
  LONG lPeriod,//后续每次触发的间隔,毫秒级别
  PTIMERAPCROUTINE pfnCompletionRoutine,//APC处理函数
  LPVOID lpArgToCompletionRoutine,//APC参加
  BOOL fResume);//休眠标识

    pDueTime - 正值表示绝对时间,负值表示相对于现在的时间间隔
    lPeriod - 0 定时器不再有后续触发,大于 0 按照间隔触发
      pDueTime | lPeriod | lPeriod ...
    2.3 等候定时器
      WaitForSingleObject
      WaitForMultipleObjects
    2.4 关闭定时器
      CloseHandle
    2.5 APC 定时器(异步调用处理)

VOID CALLBACK TimerAPCProc(
  LPVOID lpArgToCompletionRoutine,//data value
  DWORD dwTimerLowValue,// timer low value
  DWORD dwTimerHighValue);//timer high value

    2.6 其它
      OpenWaitableTimer 打开
      CancelWaitableTimer 取消

View Code
 1 #include "stdafx.h"
 2 
 3 #define _WIN32_WINNT 0x0400
 4 
 5 #include "windows.h"
 6 
 7 HANDLE g_hTimer = NULL;
 8 
 9 DWORD WINAPI TimerThread( LPVOID pParam )
10 {
11     while( 1 )
12     {
13         WaitForSingleObject( g_hTimer, INFINITE );
14         printf( "Hello Timer\n" );
15     }
16 
17     return 0;
18 }
19 
20 
21 void Create( )
22 {    //创建定时器
23     g_hTimer = CreateWaitableTimer( NULL, FALSE, NULL );
24     //设置定时器
25     UINT64 nDueTime = -100000000;
26     SetWaitableTimer( g_hTimer, 
27         (PLARGE_INTEGER)&nDueTime, 1000, //nDueTime是第一次触发的时间(纳秒),1000是以后触发间隔(毫秒)
28         NULL, NULL, FALSE );
29     //创建等候线程
30     DWORD dwThreadID = 0;
31     HANDLE hThread = CreateThread( NULL, 0,
32         TimerThread, NULL, 0, &dwThreadID );
33     WaitForSingleObject( hThread, INFINITE );
34     //关闭定时器
35     CloseHandle( g_hTimer );
36 }
37 
38 VOID CALLBACK TimerProc(
39   LPVOID lpArgToCompletionRoutine,
40   DWORD  dwTimerLowValue,
41   DWORD  dwTimerHighValue )       
42 {
43     printf( "------APC TimerProc--------\n" );
44 }
45 
46 void APCTimer( )
47 {    //创建定时器
48     HANDLE hTimer = CreateWaitableTimer( NULL, FALSE, NULL );
49     //设置定时器
50     UINT64 nDueTime = -10000000;
51     SetWaitableTimer( hTimer, 
52         (PLARGE_INTEGER)&nDueTime, 1000,
53         TimerProc, NULL, FALSE );
54     //
55     while( 1 )
56     {
57         SleepEx( -1, TRUE ); //阻塞main()函数,但是waitabletimer的消息还是能执行。说明这是另外一个消息队列
58     }    
59     
60     //关闭句柄
61     CloseHandle( hTimer );
62 }
63 
64 
65 int main(int argc, char* argv[])
66 {
67     Create( );
68     //APCTimer( );
69     
70     return 0;
71 }

 

转载于:https://www.cnblogs.com/wjay/archive/2012/10/19/2729596.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值