2013-11-22 60 views
1

我刚刚意识到我的APC被另一个线程中断。 所以在这一点上我想知道这可能是怎么回事。 正如我理解的APCs的概念:异步过程调用被另一个线程中断?

  • 一个APC不能由普通用户模式线程
  • 的APC被尽快调度中断其由函数QueueUserAPC()
  • 的APC具有请求运行至完成语义

所以这是我的初步情况: 我有一个多线程应用程序(1个主线程,1个接待线程)。 低优先级的接收线程正在从外部源接收数据。 接收线程也通过使用WaitForSingleObject()重新激活。收到的数据存储在共享的std::list中。主线程没有任何效果。 每x毫秒都会发生一个特殊事件,导致接收线程分派APC。 此APC正在主线程的上下文中运行。

所以这里是整个情况的一个例子伪源代码。

class Example { 

public: 
    Example(void) { 
    ::DuplicatHandle(
     ::GetCurrentProcess(), 
     ::GetCurrentThread(), 
     ::GetCurrentProcess(), 
     &m_mainthreadHandle, 
     THREAD_SET_CONTEXT, 
     FALSE, 
     0); 
    } 

    void run(void) { 
    ::WaitForSingleObjectEx(m_apcActivation); 
    } 

protected: 

private: 
    void rxThread(void) { 
    // this seems to be called during the apcRoutine() is running 
    // as result the shared list m_rxList is corrupted! 
    ::WaitForSingleObject(m_externalActivation); 

    Data data = externalReceive(); 

    if(data.attribute == SPECIAL) { 
     ::QueueUserAPC(apcRoutine, m_mainthreadHandle, 0); 
    } else { 
     m_rxList.push_front(data); 
    } 
    } 

    void apcRoutine(void) { 
    while(!m_rxList.empty()) { 
     m_rxList.front().print(); 
     m_rxList.pop_front(); 
    } 
    } 


    std::list<Data> m_rxList; 
    HANDLE   m_externalActivation; 
    HANDLE   m_apcActivation; 
    HANDLE   m_mainthreadHandle; 

}; 


void main(void) { 

    Example e; 

    e.run(); 

} 

我的问题是: 是否有可能,前台线程WaitForSingleObject()中断APC? 如果是,为什么?

回答

5

你似乎对APC有一些误解。

有两种(实际上是三种)APC,usermode和kernelmode(具有两种不同的优先级)APC。

用户模式APC(如您在代码中使用的APC)的行为与内核模式APC的行为不同。特别是:

  • 它们不预先线程,
  • 当你调用QueueUserAPC除非目标线程已阻塞在报警等待他们不立即执行。相反,APCs排队排队
  • 它们只在线程进入警戒等待或调用NtTestAlert时才运行。
  • 它们不是不可抢占的,事实上它们本身并没有什么特别的东西。他们只是回调,你可以排队到一个线程和哪些在定义良好的时间被调用。
  • 他们不保证运行完成,但他们保证有序执行。
  • 无法强制另一个线程执行排队的APC。目标线程必须使其自身的APC可运行。尽管存在无证函数NtAlertThread,但它不会像预期的那样工作,也不会NtAlertResumeThread

内核模式的APC,另一方面做抢占用户模式线程,并且不中断他们(和APC_LEVEL装甲运兵车是不可中断的PASSIVE_LEVEL的APC其一)。


如果是这样的话,那也是相当荒谬的。这样,您可以完全颠覆使用APC的调度程序,消耗不确定数量的CPU时间 - 无论进程优先级,特权或配额如何。

+0

很遗憾,我只能奖励+1 :( –