Windows线程API —CreateTimerQueueTimer/DeleteTimerQueueTimer的使用_#include

问题代码:

Windows线程API —CreateTimerQueueTimer/DeleteTimerQueueTimer的使用_死锁_02

1 #include<windows.h>
 2 #include<iostream>
 3 #include<thread>
 4 HANDLE h1;
 5 HANDLE h2;
 6 
 7 void CALLBACK test(PVOID a, BOOLEAN b)
 8 {
 9     std::cout << "This a test function excuted by Thread:" << std::this_thread::get_id()<< std::endl;
10     //std::cout << "Here we try to delete timer in Thread:" << std::this_thread::get_id() << std::endl;
11     if (0 == DeleteTimerQueueTimer(NULL, h1, INVALID_HANDLE_VALUE))
12     {
13         std::cout << "Timer  Deleted Failed in Thread:" << std::this_thread::get_id() << std::endl;
14     }
15     std::cout << "Timer  Deleted Successfully in Thread:" << std::this_thread::get_id() << std::endl;
16 
17 }
18 void CALLBACK test1(PVOID l, BOOLEAN t)
19 {
20     std::cout << "This a test1 function excuted by Thread:" << std::this_thread::get_id() << std::endl;
21 }
22 
23 int main()
24 {
25     
26     std::cout << "******This is a Test for TimeQueueTimer in Windows API******" << std::endl;
27     std::cout << "Main thread is executed by thread: " << std::this_thread::get_id() << std::endl;
28     //test(PVOID(1), TRUE);
29     try
30     {
31         CreateTimerQueueTimer(&h1, NULL, WAITORTIMERCALLBACK(test), NULL, 0, 1000, WT_EXECUTEINTIMERTHREAD);
32         //Sleep(1000);
33 
34         CreateTimerQueueTimer(&h2, NULL, WAITORTIMERCALLBACK(test1), NULL, 0, 1000, WT_EXECUTEINTIMERTHREAD);
35 
36 
37         //CreateTimerQueueTimer(&h1, NULL, [](PVOID lpParameter, BOOLEAN TimerOrWaitFired) {
38         //    test(lpParameter, TimerOrWaitFired); // Call your original test function from within the lambda
39         //    }, NULL, 0, 1000, WT_EXECUTEINTIMERTHREAD);
40 
41     }
42     catch (const std::exception& e)
43     {
44         std::cout << "something error with the timer: " << e.what() << std::endl;
45     }
46 
47 
48     if (std::cin.get())
49     {
50         if (0 == DeleteTimerQueueTimer(NULL, h2, INVALID_HANDLE_VALUE))
51         {
52             std::cout << "Timer  Deleted Failed in Thread:" << std::this_thread::get_id() << std::endl;
53         }
54         std::cout << "Timer  Deleted Successfully in Thread:" << std::this_thread::get_id() << std::endl;
55 
56     };
57     Sleep(1000);
58 
59     return 0;
60 }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.

Windows线程API —CreateTimerQueueTimer/DeleteTimerQueueTimer的使用_死锁_03

Main()函数中test1回调无法执行!

问题分析:

CreateTimerQueueTimerDeleteTimerQueueTimer 分别负责线程的开启和中止,函数定义如下:

Windows线程API —CreateTimerQueueTimer/DeleteTimerQueueTimer的使用_ios_04

BOOL CreateTimerQueueTimer(
  [out]          PHANDLE             phNewTimer,
  [in, optional] HANDLE              TimerQueue,
  [in]           WAITORTIMERCALLBACK Callback,
  [in, optional] PVOID               Parameter,
  [in]           DWORD               DueTime,
  [in]           DWORD               Period,
  [in]           ULONG               Flags
);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

Windows线程API —CreateTimerQueueTimer/DeleteTimerQueueTimer的使用_ios_05

BOOL DeleteTimerQueueTimer(
  [in, optional] HANDLE TimerQueue,
  [in]           HANDLE Timer,
  [in, optional] HANDLE CompletionEvent
);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

主线程中分别利用CreateTimerQueueTimer开启后台线程调用回调test()和test1(),并在test()调用中结束调用。由于DeleteTimerQueueTimerCompletionEvent中使用的是INVALID_HANDLE_VALUE,导致线程会等待所有timer线程执行结束,才能返回。而当前执行回调的线程等不到自己结束,陷入死锁。因为CreateTimerQueueTimerFlag参数使用的是WT_EXECUTEINTIMERTHREAD,导致test1回调和test使用的是同一线程,而test线程已经死锁,所以test1也无法得到执行

解决方案:

  1. 不应该在回调中调用DeleteTimerQueueTimer中止线程
  2. 如果必须在回调中中止线程,CompletionEvent应设为NULL,标记当前线程结束后,直接返回0(执行失败),回调执行完,不再继续执行
  3. CreateTimerQueueTimer使用Flag WT_EXECUTEDEFAULT开启新线程,即使上一个timer线程死锁,第二个线程仍可以执行