在QueueUserAPC中指定的回调不会被调用

Eta*_*tan 4 c++ windows multithreading signals interrupt

在我的代码中,我用它QueueUserAPC中断当前工作中的主线程,以便在回到之前的工作之前先调用一些回调.

std::string buffer;
std::tr1::shared_ptr<void> hMainThread;
VOID CALLBACK myCallback (ULONG_PTR dwParam) {
    FILE * f = fopen("somefile", "a");
    fprintf(f, "CALLBACK WAS INVOKED!\n");
    fclose(f);
}
void AdditionalThread () {
    // download some file using synchronous wininet and store the
    // HTTP response in buffer
    QueueUserAPC(myCallback, hMainThread.get(), (ULONG_PTR)0);
}
void storeHandle () {
    HANDLE hUnsafe;
    DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), 
        GetCurrentProcess(), &hUnsafe, 0, FALSE, DUPLICATE_SAME_ACCESS);
    hMainThread.reset(hUnsafe, CloseHandle);
}
void startSecondThread () {
    CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)AdditionalThread, 0, 0, NULL);
}
Run Code Online (Sandbox Code Playgroud)

storeHandlestartSecondThread暴露给Lua解释器,它在主线程中与其他东西一起运行.我现在做的是

  1. storeHandle从我的Lua口译员调用.DuplicateHandle返回非零值,因此成功.
  2. startSecondThread从我的Lua口译员调用.额外的线程正确启动,并QueueUserAPC返回一个非零值,说明一切顺利.
  3. 据我所知QueueUserAPC,myCallback现在应该从主线程调用.但事实并非如此.

如果QueueUserAPC是达到目标的正确方法(==>查看我的其他问题):

  • 我怎样才能使这个工作?

如果我应该用其他方法来中断主线程:

  • 我应该使用其他什么方法?(请注意,我不想在主线程中使用pull -ing方法进行此类WaitForSingleObject或轮询.我希望附加线程尽快其数据直接送到主线程中.)

Han*_*ant 12

是的,QueueUserAPC不是这里的解决方案.它的回调只会在线程阻塞并且程序员明确允许等待是警报时运行.这不太可能.

我对发布解决方案犹豫不决,因为它会给你带来巨大的麻烦.您可以使用SuspendThread(),GetThreadContext(),SetThreadContext()和ResumeThread()实现线程中断.关键是将CONTEXT.Eip值保存在线程的调用堆栈中,并将其替换为中断函数的地址.

你不能做这项工作的原因是因为你会有可怕的重入问题.你无法猜测你将在哪个执行点中断线程.它可能正好在它改变状态的中间,你需要如此糟糕的状态,你正在考虑这样做.没有办法不陷入这个陷阱,你不能用互斥锁或诸如此类的东西来阻止它.它也很难诊断,因为它会长时间工作,然后当中断时间恰好不幸时随机失败.

线程必须处于众所周知的状态才能安全地运行注入的代码.之前已经多次提到传统的一个:当一个线程正在抽取一个消息循环时,它是隐式空闲的,并没有做任何危险的事情.QueueUserAPC具有相同的方法,一个线程明确地向操作系统发出信号,表明它是一个可以安全执行回调的状态.通过阻止(不执行危险代码)和设置bAlertable标志.

线程必须明确表示它处于安全状态.没有安全的推模型,只有拉动.