user-0 提问: apc异步过程调用的次数

回复:
user: user-1
content: 引用When you are using a waitable timer with an APC, the thread that sets the timer should not wait on the handle of the timer. By doing so, you would cause the thread to wake up as a result of the timer becoming signaled rather than as the result of an entry being added to the APC queue. As a result, the thread is no longer in an alertable state and the completion routine is not called. In the following code, the call to SleepEx awakens the thread when an entry is added to the thread's APC queue after the timer is set to the signaled state.  这段话怎么理解？  也就是说如果如果你通过completion routine调用SetWaitableTimer的话，不要用WaitFor...等待这个waitabletimer的变成signal, 因为这个timer只有时间到了才会signal（先）然后才queue APC（后）, 但是因为你wait的函数已经等到它signal了而被唤醒了，当前线程不再处于alertable状态了， APC只有等待下一轮alertable wait时才有机会执行，这样你等于漏了一次OnTimer()  另外APC和SleepEx的次数没有关系，即使你只SleepEx一次，所有队列中的APC（哪怕有几十个）都会依次得到执行并且队列会清空。

user: user-1
content: 1. 每个APC只会执行一次，你的测试代码执行两次是因为SetWaitableTimer投递了两个APC   引用 楼主 u012879787 的回复:问题1. apc会执行几次，  代码测试后，发现2次，为什么是2次。  apc的执行次数是与 sleepex的调用次数有关系吗？   1. 每个APC只会执行一次，你的测试代码执行两次是因为SetWaitableTimer投递了两个APC  引用 楼主 u012879787 的回复:问题2。  by  a handle becoming signaled  是指waitabletimer有信号吗？  如果是的话，什么时候，会为signaled呢？  感觉只有超时才会触发。  是的，waitabletimer本身就有信号 当SetWaitableTimer到时间后就会signal. 但是如果没人wait它的话这个signal不会改变而是一直处于signal状态。另外waitabletimer到时间后如果你设置了completion routine那么它还会投递APC然后继续下一轮计时。  3. (最重要的问题） apc的效率在哪里？ 虽然目前没有能力查看底层代码，我也能猜测到， 线程的apc调用无非就是 用一个新的线程去调用这些apc函数而已，  注意： 你的线程， 依然有sleepex函数下面的代码依然不会执行。  只有异步过程全部调用完毕，才会去执行 sleepex下面的代码。  何来效率？   实在看不出效率来？   [/quote]  APC的效率主要体现在内核，内核中随时随地有大量的APC在调度。另外APC不需要一个新的线程去执行，它就在你当前线程中执行，只不过是在你wait函数调用从内核返回用户层的时候，当前线程内等待的APC都会先执行并且APC队列会清空，然后继续执行你线程中的代码，说起来你的线程本来就在wait，并没有执行任何代码，在你线程被唤醒时插入执行一点额外代码当然是最节省资源的方法，不需要额外耗时的线程调度和线程切换参与。

user: user-2
content: 引用 1 楼 u012879787 的回复:[quote=引用 楼主 u012879787 的回复:] 代码来自：http://msdn.microsoft.com/en-us/library/windows/desktop/ms686898(v=vs.85).aspx  网址：  http://www.vckbase.com/index.php/wv/1304  问题1. apc会执行几次，  代码测试后，发现2次，为什么是2次。  apc的执行次数是与 sleepex的调用次数有关系吗？   问题2。  each thread has an APC queue. If there is an entry in the thread's APC queue at the time that one of the alertable functions is called, the thread is not put to sleep. Instead, the entry is removed from the APC queue and the completion routine is called. If no entry exists in the APC queue, the thread is suspended until the wait is satisfied. The wait can be satisfied by adding an entry to the APC queue, by a timeout, or by a handle becoming signaled. If the wait is satisfied by an entry in the APC queue, the thread is awakened and the completion routine is called. In this case, the return value of the function is WAIT_IO_COMPLETION.  by  a handle becoming signaled  是指waitabletimer有信号吗？  如果是的话，什么时候，会为signaled呢？  感觉只有超时才会触发。  3. (最重要的问题） apc的效率在哪里？ 虽然目前没有能力查看底层代码，我也能猜测到， 线程的apc调用无非就是 用一个新的线程去调用这些apc函数而已，  注意： 你的线程， 依然有sleepex函数下面的代码依然不会执行。  只有异步过程全部调用完毕，才会去执行 sleepex下面的代码。  何来效率？   实在看不出效率来？    #define UNICODE 1 #define _UNICODE 1  #include <windows.h> #include <stdio.h> #include <tchar.h>  #define _SECOND 10000000  typedef struct _MYDATA {    TCHAR *szText;    DWORD dwValue; } MYDATA;  VOID CALLBACK TimerAPCProc(    LPVOID lpArg,               // Data value    DWORD dwTimerLowValue,      // Timer low value    DWORD dwTimerHighValue )    // Timer high value  {    // Formal parameters not used in this example.    UNREFERENCED_PARAMETER(dwTimerLowValue);    UNREFERENCED_PARAMETER(dwTimerHighValue);     MYDATA *pMyData = (MYDATA *)lpArg;     _tprintf( TEXT("Message: %s\nValue: %d\n\n"), pMyData->szText,           pMyData->dwValue );    MessageBeep(0);  }  int main( void )  {    HANDLE          hTimer;    BOOL            bSuccess;    __int64         qwDueTime;    LARGE_INTEGER   liDueTime;    MYDATA          MyData;     MyData.szText = TEXT("This is my data");    MyData.dwValue = 100;     hTimer = CreateWaitableTimer(            NULL,                   // Default security attributes            FALSE,                  // Create auto-reset timer            TEXT("MyTimer"));       // Name of waitable timer    if (hTimer != NULL)    {       __try        {          // Create an integer that will be used to signal the timer           // 5 seconds from now.          qwDueTime = -5 * _SECOND;           // Copy the relative time into a LARGE_INTEGER.          liDueTime.LowPart  = (DWORD) ( qwDueTime & 0xFFFFFFFF );          liDueTime.HighPart = (LONG)  ( qwDueTime >> 32 );           bSuccess = SetWaitableTimer(             hTimer,           // Handle to the timer object             &liDueTime,       // When timer will become signaled             2000,             // Periodic timer interval of 2 seconds             TimerAPCProc,     // Completion routine             &MyData,          // Argument to the completion routine             FALSE );          // Do not restore a suspended system           if ( bSuccess )           { for(int i = 0; i < 2; i++)           //  for ( ; MyData.dwValue < 1000; MyData.dwValue += 100 )              {                SleepEx(                   INFINITE,     // Wait forever                   TRUE );       // Put thread in an alertable state             }           }           else           {             printf("SetWaitableTimer failed with error %d\n", GetLastError());          }        }        __finally        {          CloseHandle( hTimer );       }    }     else     {       printf("CreateWaitableTimer failed with error %d\n", GetLastError());    }     return 0; }      When you are using a waitable timer with an APC, the thread that sets the timer should not wait on the handle of the timer. By doing so, you would cause the thread to wake up as a result of the timer becoming signaled rather than as the result of an entry being added to the APC queue. As a result, the thread is no longer in an alertable state and the completion routine is not called. In the following code, the call to SleepEx awakens the thread when an entry is added to the thread's APC queue after the timer is set to the signaled state.  这段话怎么理解？ [/quote]     引用 楼主 u012879787 的回复:代码来自：http://msdn.microsoft.com/en-us/library/windows/desktop/ms686898(v=vs.85).aspx  网址：  http://www.vckbase.com/index.php/wv/1304  问题1. apc会执行几次，  代码测试后，发现2次，为什么是2次。  apc的执行次数是与 sleepex的调用次数有关系吗？   问题2。  each thread has an APC queue. If there is an entry in the thread's APC queue at the time that one of the alertable functions is called, the thread is not put to sleep. Instead, the entry is removed from the APC queue and the completion routine is called. If no entry exists in the APC queue, the thread is suspended until the wait is satisfied. The wait can be satisfied by adding an entry to the APC queue, by a timeout, or by a handle becoming signaled. If the wait is satisfied by an entry in the APC queue, the thread is awakened and the completion routine is called. In this case, the return value of the function is WAIT_IO_COMPLETION.  by  a handle becoming signaled  是指waitabletimer有信号吗？  如果是的话，什么时候，会为signaled呢？  感觉只有超时才会触发。  3. (最重要的问题） apc的效率在哪里？ 虽然目前没有能力查看底层代码，我也能猜测到， 线程的apc调用无非就是 用一个新的线程去调用这些apc函数而已，  注意： 你的线程， 依然有sleepex函数下面的代码依然不会执行。  只有异步过程全部调用完毕，才会去执行 sleepex下面的代码。  何来效率？   实在看不出效率来？    #define UNICODE 1 #define _UNICODE 1  #include <windows.h> #include <stdio.h> #include <tchar.h>  #define _SECOND 10000000  typedef struct _MYDATA {    TCHAR *szText;    DWORD dwValue; } MYDATA;  VOID CALLBACK TimerAPCProc(    LPVOID lpArg,               // Data value    DWORD dwTimerLowValue,      // Timer low value    DWORD dwTimerHighValue )    // Timer high value  {    // Formal parameters not used in this example.    UNREFERENCED_PARAMETER(dwTimerLowValue);    UNREFERENCED_PARAMETER(dwTimerHighValue);     MYDATA *pMyData = (MYDATA *)lpArg;     _tprintf( TEXT("Message: %s\nValue: %d\n\n"), pMyData->szText,           pMyData->dwValue );    MessageBeep(0);  }  int main( void )  {    HANDLE          hTimer;    BOOL            bSuccess;    __int64         qwDueTime;    LARGE_INTEGER   liDueTime;    MYDATA          MyData;     MyData.szText = TEXT("This is my data");    MyData.dwValue = 100;     hTimer = CreateWaitableTimer(            NULL,                   // Default security attributes            FALSE,                  // Create auto-reset timer            TEXT("MyTimer"));       // Name of waitable timer    if (hTimer != NULL)    {       __try        {          // Create an integer that will be used to signal the timer           // 5 seconds from now.          qwDueTime = -5 * _SECOND;           // Copy the relative time into a LARGE_INTEGER.          liDueTime.LowPart  = (DWORD) ( qwDueTime & 0xFFFFFFFF );          liDueTime.HighPart = (LONG)  ( qwDueTime >> 32 );           bSuccess = SetWaitableTimer(             hTimer,           // Handle to the timer object             &liDueTime,       // When timer will become signaled             2000,             // Periodic timer interval of 2 seconds             TimerAPCProc,     // Completion routine             &MyData,          // Argument to the completion routine             FALSE );          // Do not restore a suspended system           if ( bSuccess )           { for(int i = 0; i < 2; i++)           //  for ( ; MyData.dwValue < 1000; MyData.dwValue += 100 )              {                SleepEx(                   INFINITE,     // Wait forever                   TRUE );       // Put thread in an alertable state             }           }           else           {             printf("SetWaitableTimer failed with error %d\n", GetLastError());          }        }        __finally        {          CloseHandle( hTimer );       }    }     else     {       printf("CreateWaitableTimer failed with error %d\n", GetLastError());    }     return 0; }    定时器到时候，会插入一个apc到apc队列中。  sleepex让线程处于可提醒状态，由于apc不为空，所以调度线程，执行apc，  然后回到for， 由于再次调用sleepex，插入apc，执行apc。    所以是2次。

user: user-2
content: 异步体现效率？

user: user-0
content: 引用 楼主 u012879787 的回复:代码来自：http://msdn.microsoft.com/en-us/library/windows/desktop/ms686898(v=vs.85).aspx  网址：  http://www.vckbase.com/index.php/wv/1304  问题1. apc会执行几次，  代码测试后，发现2次，为什么是2次。  apc的执行次数是与 sleepex的调用次数有关系吗？   问题2。  each thread has an APC queue. If there is an entry in the thread's APC queue at the time that one of the alertable functions is called, the thread is not put to sleep. Instead, the entry is removed from the APC queue and the completion routine is called. If no entry exists in the APC queue, the thread is suspended until the wait is satisfied. The wait can be satisfied by adding an entry to the APC queue, by a timeout, or by a handle becoming signaled. If the wait is satisfied by an entry in the APC queue, the thread is awakened and the completion routine is called. In this case, the return value of the function is WAIT_IO_COMPLETION.  by  a handle becoming signaled  是指waitabletimer有信号吗？  如果是的话，什么时候，会为signaled呢？  感觉只有超时才会触发。  3. (最重要的问题） apc的效率在哪里？ 虽然目前没有能力查看底层代码，我也能猜测到， 线程的apc调用无非就是 用一个新的线程去调用这些apc函数而已，  注意： 你的线程， 依然有sleepex函数下面的代码依然不会执行。  只有异步过程全部调用完毕，才会去执行 sleepex下面的代码。  何来效率？   实在看不出效率来？    #define UNICODE 1 #define _UNICODE 1  #include <windows.h> #include <stdio.h> #include <tchar.h>  #define _SECOND 10000000  typedef struct _MYDATA {    TCHAR *szText;    DWORD dwValue; } MYDATA;  VOID CALLBACK TimerAPCProc(    LPVOID lpArg,               // Data value    DWORD dwTimerLowValue,      // Timer low value    DWORD dwTimerHighValue )    // Timer high value  {    // Formal parameters not used in this example.    UNREFERENCED_PARAMETER(dwTimerLowValue);    UNREFERENCED_PARAMETER(dwTimerHighValue);     MYDATA *pMyData = (MYDATA *)lpArg;     _tprintf( TEXT("Message: %s\nValue: %d\n\n"), pMyData->szText,           pMyData->dwValue );    MessageBeep(0);  }  int main( void )  {    HANDLE          hTimer;    BOOL            bSuccess;    __int64         qwDueTime;    LARGE_INTEGER   liDueTime;    MYDATA          MyData;     MyData.szText = TEXT("This is my data");    MyData.dwValue = 100;     hTimer = CreateWaitableTimer(            NULL,                   // Default security attributes            FALSE,                  // Create auto-reset timer            TEXT("MyTimer"));       // Name of waitable timer    if (hTimer != NULL)    {       __try        {          // Create an integer that will be used to signal the timer           // 5 seconds from now.          qwDueTime = -5 * _SECOND;           // Copy the relative time into a LARGE_INTEGER.          liDueTime.LowPart  = (DWORD) ( qwDueTime & 0xFFFFFFFF );          liDueTime.HighPart = (LONG)  ( qwDueTime >> 32 );           bSuccess = SetWaitableTimer(             hTimer,           // Handle to the timer object             &liDueTime,       // When timer will become signaled             2000,             // Periodic timer interval of 2 seconds             TimerAPCProc,     // Completion routine             &MyData,          // Argument to the completion routine             FALSE );          // Do not restore a suspended system           if ( bSuccess )           { for(int i = 0; i < 2; i++)           //  for ( ; MyData.dwValue < 1000; MyData.dwValue += 100 )              {                SleepEx(                   INFINITE,     // Wait forever                   TRUE );       // Put thread in an alertable state             }           }           else           {             printf("SetWaitableTimer failed with error %d\n", GetLastError());          }        }        __finally        {          CloseHandle( hTimer );       }    }     else     {       printf("CreateWaitableTimer failed with error %d\n", GetLastError());    }     return 0; }      When you are using a waitable timer with an APC, the thread that sets the timer should not wait on the handle of the timer. By doing so, you would cause the thread to wake up as a result of the timer becoming signaled rather than as the result of an entry being added to the APC queue. As a result, the thread is no longer in an alertable state and the completion routine is not called. In the following code, the call to SleepEx awakens the thread when an entry is added to the thread's APC queue after the timer is set to the signaled state.  这段话怎么理解？