Windows异步过程调用(APC)

原文转载自:http://blog.sina.com.cn/s/blog_6c617ee301017nhr.html,感谢原作者。


apc可以看成就是内核里的定时器,为了给自己一个在本函数返回后还能执行的一次机会,有很多操作是需要在函数返回后才能执行.
类似于析构函数但不完全是。
apc的最大特点就是在本函数返回后才执行,而且是在本线程中。
而内核提供的原生的定时器,执行的环境可能就不是原始的线程了。
windows天生就是个异步框架,里面大量的设计都是为异步而设计,比如IRP,就是贯穿整个windows的异步框架
apc它的执行时机有多,比如在线程wait、线程切换到应用层、线程被挂起等等等等,而且apc也分几个层次的优先级.就是说apc一般是不太需要立马执行的低优先级的函数。所以一旦线程有空隙了,windows就会执行一下
windows在执行完线程的主要任务何后,顺便把apc队列执行一遍

一:皮毛
每个线程都会维护一个线程apc队列,通过 QueueUserAPC把一个apc函数添加到指定线程的apc队列
DWORD WINAPI QueueUserAPC(
   _In_   PAPCFUNC pfnAPC,
   _In_   HANDLE hThread,
   _In_   ULONG_PTR dwData
);

VOID CALLBACK APCProc(
   _In_   ULONG_PTR dwParam
);

Each thread has its own APC queue. The queuing of an APC is a request for the thread to call the APC function. The operating system issues a software interrupt to direct the thread to call the APC function.
每个线程都由她自己的APC队列,这个APC队列纪录了要求线程去执行的一些APC函数。OS发出一个软中断去执行这些APC函数。

When a user-mode APC is queued, the thread is not directed to call the APC function unless it is in an alertable state.
对于用户模式下是APC队列,当线程处在alertable状态时才去执行这些APC函数。
 
  A thread enters an alertable state by using SleepEx, SignalObjectAndWait, WaitForSingleObjectEx, WaitForMultipleObjectsEx , or MsgWaitForMultipleObject sEx to perform an alertable wait operation.
一个线程内部使用SleepEx, SignalObjectAndWait, WaitForSingleObjectEx, WaitForMultipleObjectsEx , or MsgWaitForMultipleObject sEx 等函数把自己挂起时就是进入alertable状态,此时执行APC队列的函数。
*Ex(..,TRUE)最后一个参数为TRUE才进入alertable状态,不带Ex的这些函数默认FALSE掉用相应的*Ex不进入alertable状态。
 
After the thread is in an alertable state, the thread handles all pending APCs in first in, first out (FIFO) order, and the wait operation returns WAIT_IO_COMPLETION. 
线程在alertable状态时按先进先出执行apc,
线程等待的内核对象触发后相应*Ex函数返回值为WAIT_IO_COMPLETION,线程被激活。
If an application queues an APC before the thread begins running, the thread begins by calling the APC function. After the thread calls an APC function, it calls the APC functions for all APCs in its APC queue.(没看明白)
 
When the thread is terminated using the ExitThread or TerminateThread function, the APCs in its APC queue are lost. The APC functions are not called.
 
It is possible to sleep or wait for an object within the APC.(在apc之内去sleep或wait一个对象是可以的)
 
  If you perform an alertable wait inside an APC, it will recursively dispatch the APCs. This can cause a stack overflow.(如果你在APC里执行一个alertable,他将按APC路径递归。这可能引起堆栈溢出)
 

二:apc过程分析
#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <process.h>
using namespace std;
VOID WINAPI APCFunc(ULONG_PTR dwParam)
{
       cout<<"APCFunc:处理APC函数ing"<<endl;
  Sleep(2000);
  cout<<"APCFunc:Sleep了2000,处理APC函数ing"<<endl;
}
VOID WINAPI APCFunc2(ULONG_PTR dwParam)
{
       cout<<"APCFunc2:处理APC函数2ing"<<endl;
  Sleep(100);
  cout<<"APCFunc2:处理APC函数2ing"<<endl;
 
}
DWORD WINAPI ThreadFun(PVOID pvParam)
{
       HANDLE hEvent   = (HANDLE)pvParam;
  Sleep(100);
  cout<<"ThreadFun:WaitForSingleObjectEx(hEvent,INFINITE,TRUE);"<<endl;
       DWORD dw = WaitForSingleObjectEx(hEvent,INFINITE,TRUE);
//*Ex函数把线程设置为alertable状态
       if(dw == WAIT_OBJECT_0)
       {
               cout<<"ThreadFun:事件触发"<<endl;
       }
       if(dw == WAIT_IO_COMPLETION)
       {
               //如果线程至少处理了APC队列中的一项
               cout<<"ThreadFun:APC队列中APC函数执行完,等待函数返回WAIT_IO_COMPLETION激活该线程继续执行"<<endl;
             
       }
       return 0;
}
int main(int argc, char* argv[])
{
  HANDLE hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
  HANDLE hThread = (HANDLE)_beginthreadex(NULL,0,(unsigned int (__stdcall *)(void *))ThreadFun,(PVOID)hEvent,0,NULL);
  //执行一些其他代码
  cout<<"main:开始"<<endl;
  //此时用户想要终止子线程
  Sleep(1000); //留出时间先让子线程进入alertable状态。
  cout<<"main:主程Sleep(1000)此时线程调用WaitForSingleObjectEx处于alertable状态"<<endl;
  QueueUserAPC(APCFunc,hThread,NULL);
  cout<<"main:QueueUserAPC(APCFunc,hThread,NULL);"<<endl;
  Sleep(1500);
  cout<<"main:主程Sleep了1500时间比APCFunc的2000短,让线程在执行完APC函数前往其中添加新的APCFunc2"<<endl;
  QueueUserAPC(APCFunc2,hThread,NULL);
  cout<<"QueueUserAPC(APCFunc2,hThread,NULL);"<<endl;
  WaitForSingleObject(hThread,INFINITE);
  cout<<"main:WaitForSingleObject(hThread,INFINITE);"<<endl;
  system("pause");
  return 0;
}

main()在Sleep(1000); 的时候确保新线程调WaitForSingleObjectEx进入alertable状态以执行APC函数。应为返回dw的不是WAIT_OBJECT_0所以不是hEvent被激活触发,而是APC队列中函数执行完毕触发的。


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Windows APC(Asynchronous Procedure Call)是一种异步过程调用机制,它允许一个线程在另一个线程上异步执行指定的函数。APC 机制是 Windows 操作系统中非常重要的一部分,它被广泛用于实现各种系统功能,例如异步 I/O、线程池等。 在 Windows 中,每个线程都有一个 APC 队列,该队列中存储了需要在该线程上异步执行的函数。当一个线程进入 Alertable 状态时(例如调用 Sleep、WaitForSingleObject 等函数),它会检查自己的 APC 队列中是否有待处理的 APC,如果有,则会立即执行 APC 中指定的函数。 APC 机制的具体原理如下: 1. 创建 APC 对象 首先,创建一个 APC 对象,该对象包含要在目标线程上执行的函数和参数。 2. 将 APC 对象插入到目标线程的 APC 队列 使用 QueueUserAPC 函数将 APC 对象插入到目标线程的 APC 队列中。当目标线程进入 Alertable 状态时,它会检查自己的 APC 队列中是否有待处理的 APC,如果有,则会立即执行 APC 中指定的函数。 3. 触发目标线程进入 Alertable 状态 为了让目标线程进入 Alertable 状态,可以使用 Sleep、WaitForSingleObject 等函数来实现。当目标线程进入 Alertable 状态时,它会检查自己的 APC 队列中是否有待处理的 APC,如果有,则会立即执行 APC 中指定的函数。 总之,APC 机制是 Windows 操作系统中非常重要的一部分,它提供了一种有效的异步过程调用机制,可以在不阻塞目标线程的情况下异步执行指定的函数。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值