异步过程调用

Asynchronous Procedure Calls

本文关键字:异步过程调用      更新时间:2023-10-16

我试图让APC在我的c++代码工作,但我失败了。我不知该说什么好了。在c#中,它工作得很好(逻辑上是相同的代码)。我想让线程2向线程1注入一个调用。但是在我的c++项目中,由于某些原因它不会执行。我做错了什么?

  • 线程1(主线程)
  • 线程2(子线程,需要主线程执行一个函数)


代码:

#include "stdio.h"
#include "windows.h"
#define TIME 2500
#define LAST_ERROR printf("last error: %irn", GetLastError());
HANDLE handle1, handle2;
void ThreadInfo(char* prefix = "")
{
    printf("%sthread id: %irn", prefix, GetCurrentThreadId());
}
VOID CALLBACK apc( _In_ ULONG_PTR data)
{
    ThreadInfo(" -> apc: 2 -> 1: ");
}
void run1()
{
    while (true)
    {
        Sleep(TIME);
        ThreadInfo("1: ");
        // apc
        //QueueUserAPC(apc, handle2, (ULONG_PTR) NULL);
    }
}
void run2()
{
    while (true)
    {
        Sleep(TIME);
        ThreadInfo("2: ");
        // apc
        QueueUserAPC(apc, handle1, (ULONG_PTR) NULL);
    }
}
void TestThreads()
{
    DWORD threadId;
    SECURITY_ATTRIBUTES a;
    a.nLength = 12;
    a.lpSecurityDescriptor = NULL;
    a.bInheritHandle = 1;
    DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &handle1, 0, true, 2);
    LAST_ERROR
    handle2 = CreateThread(NULL, 100000, (LPTHREAD_START_ROUTINE)run2, NULL, 0, &threadId);
    printf("handles (1, 2): %i, %irn", handle1, handle2);
    printf("ids (1, 2): %i, %irn", threadId, GetCurrentThreadId());
    printf("--------------------------------rn");
    run1();
}
int main()
{
    TestThreads();
    printf("done.");
    getchar();
    return 0;
}
  Sleep(TIME);

这是你的问题陈述。装甲运兵车很危险,它们允许代码重入。大致相当于臭名昭著的Application.DoEvents()语句,它让很多VB程序员陷入了麻烦。Windows不只是让它们运行,你必须明确你的代码是可重入的,这样APC才能安全运行而不会打乱你的程序状态。

特定的要求是你的线程处于"可报警等待状态"。进入等待状态不是问题,Sleep()调用可以做到这一点。然而,它不是一个可报警的状态。你必须用这个代替:

  SleepEx(TIME, TRUE);

修改测试程序中的run1()函数,现在您将看到APC回调被调用。与GetOverlappedResultEx(), SignalObjectAndWait(), WaitForSingleObjectEx()和WaitForMultipleObjectsEx()相比,其他winapi调用可以将线程置于alertable等待状态。是的,托管程序中的Thread.Sleep()是可唤醒的,CLR在底层调用sleeppex()。