CWinThread::PreTranslateMessage 在消息调度到 Windows 函数 TranslateMessage DispatchMessage 之前筛选消息。 CWinThread::ProcessMessageFilter 在某些消息到达应用程序之前截获这些消息。 CWinThread::ProcessWndProcException 截获由线程的消息和命令处理程序引发的所有未经处理的异常。 CWinThread::PumpMessage 包含线程的消息循环。 CWinThread::ResumeThread 递减线程的挂起计数。 CWinThread::Run 具有消息泵的线程的控制函数。 替代以自定义默认消息循环。 CWinThread::SetThreadPriority 设置当前线程的优先级。 CWinThread::SuspendThread 递增线程的挂起计数。

公共运算符

执行的主线程通常由派生自 CWinApp 的对象提供; CWinApp 派生自 CWinThread 。 其他 CWinThread 对象允许一个给定应用程序中存在多个线程。

CWinThread 支持两种常规类型的线程:工作线程和用户界面线程。 工作线程没有消息泵:例如在电子表格应用程序中执行后台计算的线程。 用户界面线程具有消息泵,并处理从系统接收的消息。 CWinApp 和派生自它的类是用户界面线程的示例。 其他用户界面线程也可以直接派生自 CWinThread

CWinThread 的对象通常存在于线程的持续时间内。 如果要修改此行为,请将 m_bAutoDelete 设置为 FALSE

CWinThread 类是使代码和 MFC 完全线程安全所必需的。 框架用来维护特定于线程的信息的线程本地数据由 CWinThread 对象管理。 由于通过这种对 CWinThread 的依赖来处理线程本地数据,因此,使用 MFC 的任何线程必须由 MFC 创建。 例如,运行时函数 _beginthread _beginthreadex 创建的线程不能使用任何 MFC API。

若要创建线程,请调用 AfxBeginThread 。 有两种形式,具体取决于你是需要工作线程还是用户界面线程。 如果需要用户界面线程,请传递给 AfxBeginThread 指向 CWinThread 派生类的 CRuntimeClass 的指针。 如果要创建工作线程,请传递给 AfxBeginThread 指向控制函数的指针和控制函数的参数。 对于工作线程和用户界面线程,可以指定用于修改优先级、堆栈大小、创建标志和安全特性的可选参数。 AfxBeginThread 将返回指向新 CWinThread 对象的指针。

通过改为调用 AfxBeginThread ,可以构造 CWinThread 派生的对象,然后调用 CreateThread 。 如果要在连续创建和终止线程执行之间重复使用 CWinThread 对象,则此双阶段构造方法非常有用。

有关 CWinThread 的详细信息,请参阅文章 使用 C++ 和 MFC 进行多线程处理 多线程处理:创建用户界面线程 多线程处理:创建工作线程 多线程处理:如何使用同步类

继承层次结构

CObject

CCmdTarget

CWinThread

标头: afxwin.h

CWinThread::CreateThread

创建要在调用进程的地址空间内执行的线程。

BOOL CreateThread(
    DWORD dwCreateFlags = 0,
    UINT nStackSize = 0,
    LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);

dwCreateFlags
指定一个用于控制线程创建的额外标志。 此标志可以包含两个值之一:

  • CREATE_SUSPENDED 以 1 的挂起计数启动线程。 如果要在线程开始运行之前初始化 CWinThread 对象的任何成员数据(例如 m_bAutoDelete 或派生类的任何成员),请使用 CREATE_SUSPENDED。 初始化完成后,使用 CWinThread::ResumeThread 启动线程运行。 在调用 CWinThread::ResumeThread 之前,线程将不会执行。

  • 0 创建后立即启动线程。

    nStackSize
    指定新线程堆栈的大小(以字节为单位)。 如果为 0,堆栈大小会默认为与进程主线程的大小相同的大小。

    lpSecurityAttrs
    指向用于指定线程安全特性的 SECURITY_ATTRIBUTES 结构。

    如果线程创建成功,则为非零值;否则为 0。

    使用 AfxBeginThread 创建线程对象并在一个步骤中执行它。 如果要在连续创建和终止线程执行之间重复使用线程对象,请使用 CreateThread

    CWinThread::CWinThread

    构造 CWinThread 对象。

    CWinThread();
    

    若要开始线程的执行,请调用 CreateThread 成员函数。 通常通过调用 AfxBeginThread 来创建线程,这将调用此构造函数和 CreateThread

    CWinThread::ExitInstance

    由框架从很少替代的 Run 成员函数中调用以退出线程的此实例,或者在调用 InitInstance 失败时由框架调用。

    virtual int ExitInstance();
    

    线程的退出代码;0 表示无错误,大于 0 的值表示错误。 可以通过调用 GetExitCodeThread 来检索此值。

    不要从除了 Run 成员函数内以外的任何位置调用此成员函数。 此成员函数仅在用户界面线程中使用。

    如果 m_bAutoDeleteTRUE,此函数的默认实现将删除 CWinThread 对象。 如果要在线程终止时执行其他清理,请替代此函数。 ExitInstance 的实现应在代码执行后调用基类的版本。

    CWinThread::GetMainWnd

    如果应用程序是 OLE 服务器,请调用此函数来检索指向应用程序的活动主窗口的指针,而不是直接引用应用程序对象的 m_pMainWnd 成员。

    virtual CWnd* GetMainWnd();
    

    此函数返回指向两种类型的窗口之一的指针。 如果线程是 OLE 服务器的一部分,并且具有在活动容器中处于就地活动状态的对象,则此函数将返回 CWinThread 对象的 CWinApp::m_pActiveWnd 数据成员。

    如果没有在容器中处于就地活动状态的对象,或者你的应用程序不是一个 OLE 服务器,则此函数返回你的线程对象的 m_pMainWnd 数据成员。

    对于用户界面线程,这等效于直接引用应用程序对象的 m_pActiveWnd 成员。

    如果您的应用程序不是 OLE 服务器,调用此函数相当于直接引用应用程序对象的 m_pMainWnd 成员。

    替代此函数以修改默认行为。

    CWinThread::GetThreadPriority

    获取此线程的当前线程优先级别。

    int GetThreadPriority();
    

    其优先级类中的当前线程优先级别。 返回的值将是以下值之一,从最高优先级到最低优先级列出:

  • THREAD_PRIORITY_TIME_CRITICAL

  • THREAD_PRIORITY_HIGHEST

  • THREAD_PRIORITY_ABOVE_NORMAL

  • THREAD_PRIORITY_NORMAL

  • THREAD_PRIORITY_BELOW_NORMAL

  • THREAD_PRIORITY_LOWEST

  • THREAD_PRIORITY_IDLE

    有关这些优先级的详细信息,请参阅 Windows SDK 中的 SetThreadPriority

    CWinThread::InitInstance

    必须替代 InitInstance 才能初始化用户界面线程的每个新实例。

    virtual BOOL InitInstance();
    

    如果初始化成功,则为非零值;否则为 0。

    通常,你会替代 InitInstance 以执行在首次创建线程时必须完成的任务。

    此成员函数仅在用户界面线程中使用。 在传递给 AfxBeginThread 的控制函数中执行工作线程初始化。

    CWinThread::IsIdleMessage

    替代此函数,使 OnIdle 在特定消息生成后不被调用。

    virtual BOOL IsIdleMessage(MSG* pMsg);
    指向正在处理的当前消息。

    如果在处理消息后应调用 OnIdle,则为非零值;否则为 0。

    默认实现不会在冗余鼠标消息和由闪烁的插入符生成的消息后调用 OnIdle

    如果应用程序创建了短计时器,则将经常调用 OnIdle,从而导致性能问题。 若要提高此类应用程序的性能,请在应用程序的 CWinApp 派生类中替代 IsIdleMessage 以检查 WM_TIMER 消息,如下所示:

    BOOL CMyWinApp::IsIdleMessage(MSG* pMsg)
       if (!CWinApp::IsIdleMessage(pMsg) || pMsg->message == WM_TIMER)
          return FALSE;
          return TRUE;
    

    以这种方式处理 WM_TIMER 将提高使用短计时器的应用程序的性能。

    CWinThread::m_bAutoDelete

    指定 CWinThread 对象是否应在线程终止时自动删除。

    BOOL m_bAutoDelete;
    

    m_bAutoDelete 数据成员是 BOOL 类型的公共变量。

    m_bAutoDelete 的值不会影响基础线程句柄的关闭方式,但它会影响关闭句柄的计时。 在销毁 CWinThread 对象时,始终关闭线程句柄。

    CWinThread::m_hThread

    附加到此 CWinThread 的线程的句柄。

    HANDLE m_hThread;
    

    m_hThread 数据成员是 HANDLE 类型的公共变量。 仅当基础内核线程对象当前存在且句柄尚未关闭时,它才有效。

    CWinThread 析构函数对 m_hThread 调用 CloseHandle。 如果当线程终止时 m_bAutoDeleteTRUECWinThread 对象会被销毁,这将使指向 CWinThread 对象及其成员变量的任何指针失效。 可能需要 m_hThread 成员来检查线程退出值,或等待信号。 若要在线程执行期间以及线程终止后保留 CWinThread 对象及其 m_hThread 成员,请在允许线程执行继续之前将 m_bAutoDelete 设置为 FALSE。 否则,在你尝试使用它之前,线程可能会终止、销毁 CWinThread 对象,并关闭句柄。 如果使用此方法,则需要负责删除 CWinThread 对象。

    CWinThread::m_nThreadID

    附加到此 CWinThread 的线程的 ID。

    DWORD m_nThreadID;
    

    m_nThreadID 数据成员是 DWORD 类型的公共变量。 仅当基础内核线程对象当前存在时,它才有效。 另请参阅有关 m_hThread 生存期的注解。

    请参阅 AfxGetThread 的示例。

    CWinThread::m_pActiveWnd

    使用此数据成员来存储指向线程的活动窗口对象的指针。

    CWnd* m_pActiveWnd;
    

    m_pActiveWnd 引用的窗口关闭时,Microsoft 基础类库将自动终止你的线程。 如果此线程是应用程序的主线程,则应用程序也将终止。 如果此数据成员是 NULL,则将继承应用程序的 CWinApp 对象的活动窗口。 m_pActiveWndCWnd* 类型的公共变量。

    通常,在替代 InitInstance 时将设置此成员变量。 在工作线程中,此数据成员的值继承自其父线程。

    CWinThread::m_pMainWnd

    使用此数据成员来存储指向线程的主窗口对象的指针。

    CWnd* m_pMainWnd;
    

    m_pMainWnd 引用的窗口关闭时,Microsoft 基础类库将自动终止你的线程。 如果此线程是应用程序的主线程,则应用程序也将终止。 如果此数据成员是 NULL,则应用程序的 CWinApp 对象的主窗口将用于确定何时终止线程。 m_pMainWndCWnd* 类型的公共变量。

    通常,在替代 InitInstance 时将设置此成员变量。 在工作线程中,此数据成员的值继承自其父线程。

    CWinThread::OnIdle

    替代此成员函数以执行空闲时间处理。

    virtual BOOL OnIdle(LONG lCount);
    

    lCount
    每当线程的消息队列为空而调用 OnIdle 时将递增的计数器。 每次处理新消息时,此计数将重置为 0。 可以使用 lCount 参数来确定在未处理消息的情况下线程空闲时间的相对长度。

    如果接收更多空闲处理时间,则为非零值;如果不再需要更多空闲处理时间,则为 0。

    当线程的消息队列为空时会在默认消息循环中调用 OnIdle。 使用替代以调用自己的后台空闲处理程序任务。

    OnIdle 应返回 0 以指示不需要额外的空闲处理时间。 每当消息队列为空而调用 OnIdle 时,lCount 参数将递增,并且在每次处理新消息时将重置为 0。 可以基于此计数调用不同的空闲例程。

    此成员函数的默认实现将从内存中释放临时对象和未使用的动态链接库。

    此成员函数仅在用户界面线程中使用。

    由于应用程序在 OnIdle 返回之前无法处理消息,因此不要在此函数中执行冗长的任务。

    CWinThread::operator HANDLE

    检索 CWinThread 对象的句柄。

    operator HANDLE() const;
    

    如果成功,则为线程对象的句柄;否则为 NULL.

    使用句柄直接调用 Windows API。

    CWinThread::PostThreadMessage

    调用以将用户定义的消息发布到另一个 CWinThread 对象。

    BOOL PostThreadMessage(
        UINT message,
        WPARAM wParam,
        LPARAM lParam);
    

    message
    用户定义的消息的 ID。

    wParam
    第一个消息参数。

    lParam
    第二个消息参数。

    如果成功,则不为 0;否则为 0。

    已发布的消息由消息映射宏 ON_THREAD_MESSAGE 映射到正确的消息处理程序。

    调用 PostThreadMessage 时,消息将放置在线程的消息队列中。 但是,由于以这种方式发布的消息与窗口不关联,因此 MFC 不会将它们调度到消息或命令处理程序。 为了处理这些消息,请替代 CWinApp 派生类的 PreTranslateMessage() 函数,并手动处理消息。

    CWinThread::PreTranslateMessage

    替代此函数,以在窗口消息调度到 Windows 函数 TranslateMessageDispatchMessage 之前筛选这些消息。

    virtual BOOL PreTranslateMessage(MSG* pMsg);
    指向包含要处理的消息的 MSG 结构

    如果消息已在 PreTranslateMessage 中完全处理且不应进一步处理,则为非零值。 如果消息应以正常方式处理,则为零。

    此成员函数仅在用户界面线程中使用。

    CWinThread::ProcessMessageFilter

    框架的挂钩函数调用此成员函数来筛选和响应某些 Windows 消息。

    virtual BOOL ProcessMessageFilter(
        int code,
        LPMSG lpMsg);
    指定挂钩代码。 此成员函数使用此代码来确定如何处理 lpMsg

    lpMsg
    指向 Windows MSG 结构的指针。

    如果消息已处理,则为非零值;否则为 0。

    挂钩函数将在事件发送到应用程序的正常消息处理之前处理事件。

    如果替代此高级功能,请确保调用基类版本以维护框架的挂钩处理。

    CWinThread::ProcessWndProcException

    每当处理程序不捕获线程的消息或命令处理程序之一中引发的异常时,框架都会调用此成员函数。

    virtual LRESULT ProcessWndProcException(
        CException* e,
        const MSG* pMsg);
    指向未处理的异常。

    指向 MSG 结构,其中包含有关导致框架引发异常的 Windows 消息的信息。

    如果生成 WM_CREATE 异常,则为 -1;否则为 0。

    请勿直接调用此成员函数。

    此成员函数的默认实现仅处理从以下消息生成的异常:

    PumpMessage 包含线程的消息循环。 PumpMessageCWinThread 调用以泵出线程的消息。 可以直接调用 PumpMessage 以强制处理消息,也可以替代 PumpMessage 以更改其默认行为。

    仅建议高级用户直接调用 PumpMessage 并替代其默认行为。

    CWinThread::ResumeThread

    调用以恢复执行由 SuspendThread 成员函数挂起的线程或使用 CREATE_SUSPENDED 标志创建的线程。

    DWORD ResumeThread();
    

    如果成功,则为线程的上一个挂起计数;否则为 0xFFFFFFFF。 如果返回值为零,则当前线程未挂起。 如果返回值为 1,则线程已挂起,但现在将重新启动。 任何大于 1 的返回值都表示线程保持挂起状态。

    当前线程的挂起计数减 1。 如果挂起计数减到 0,线程将恢复执行;否则线程将保持挂起状态。

    CWinThread::Run

    为用户界面线程提供默认消息循环。

    virtual int Run();
    

    由线程返回的 int 值。 可以通过调用 GetExitCodeThread 来检索此值。

    Run 会获取并调度 Windows 消息,直到应用程序接收 WM_QUIT 消息为止。 如果线程的消息队列当前不包含任何消息,Run 会调用 OnIdle 以执行空闲时间处理。 传入消息将转到 PreTranslateMessage 成员函数进行特殊处理,然后转到 Windows 函数 TranslateMessage 进行标准键盘转换。 最后,将调用 DispatchMessage Windows 函数。

    尽管 Run 很少被替代,但可以替代它来实现特殊行为。

    此成员函数仅在用户界面线程中使用。

    CWinThread::SetThreadPriority

    此函数在其优先级类中设置当前线程的优先级别。

    BOOL SetThreadPriority(int nPriority);
    

    nPriority
    在其优先级类中指定新的线程优先级别。 此参数必须是以下值之一,从最高优先级到最低优先级列出:

  • THREAD_PRIORITY_TIME_CRITICAL

  • THREAD_PRIORITY_HIGHEST

  • THREAD_PRIORITY_ABOVE_NORMAL

  • THREAD_PRIORITY_NORMAL

  • THREAD_PRIORITY_BELOW_NORMAL

  • THREAD_PRIORITY_LOWEST

  • THREAD_PRIORITY_IDLE

    有关这些优先级的详细信息,请参阅 Windows SDK 中的 SetThreadPriority

    如果函数成功,则为非零值;否则为 0。

    它只能在 CreateThread 成功返回后调用。

    CWinThread::SuspendThread

    递增当前线程的挂起计数。

    DWORD SuspendThread();
    

    如果成功,则为线程的上一个挂起计数;否则为 0xFFFFFFFF

    如果任何线程的挂起计数高于零,该线程将不会执行。 可以通过调用 ResumeThread 成员函数来恢复线程。

    CCmdTarget
    层次结构图
    CWinApp
    CCmdTarget

  •