我正在尝试让APC使用我的C ++代码,但是我失败了。我迷失了语言。在C#中它可以正常工作(逻辑上相同的代码)。我希望线程2在线程1中注入一个调用。但在我的C ++项目中,由于某种原因它不会执行。我做错了什么?
<小时/> 的代码:
#include "stdio.h"
#include "windows.h"
#define TIME 2500
#define LAST_ERROR printf("last error: %i\r\n", GetLastError());
HANDLE handle1, handle2;
void ThreadInfo(char* prefix = "")
{
printf("%sthread id: %i\r\n", 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, %i\r\n", handle1, handle2);
printf("ids (1, 2): %i, %i\r\n", threadId, GetCurrentThreadId());
printf("--------------------------------\r\n");
run1();
}
int main()
{
TestThreads();
printf("done.");
getchar();
return 0;
}
答案 0 :(得分:10)
Sleep(TIME);
这是您的问题陈述。 APC非常危险,它们允许代码重新进入。臭名昭着的相当于臭名昭着的Application.DoEvents()语句让很多VB程序员陷入困境。 Windows并不只是让它们运行,你必须显式你的代码是可重入的,这样APC可以安全地运行而不会搞砸你的程序状态。
具体要求是您的线程处于&#34;可警告的等待状态&#34;。进入等待状态不是问题,Sleep()调用会这样做。然而,这不是一个可警告的状态。你必须改为使用它:
SleepEx(TIME, TRUE);
修改测试程序中的run1()函数,现在您将看到调用APC回调。与GetOverlappedResultEx(),SignalObjectAndWait(),WaitForSingleObjectEx()和WaitForMultipleObjectsEx()相比,其他winapi调用可以使线程处于可警告的等待状态。是的,托管程序中的Thread.Sleep()是可警告的,CLR会调用SleepEx()。