多线程处理:MFC 编程提示

多线程应用程序比单线程应用程序的要求更严格,这是为了确保操作按预期顺序进行,并且多个线程访问的任何数据都不会损坏。 本主题介绍在使用 Microsoft 基础类 (MFC) 库进行多线程应用程序编程时避免潜在问题的方法。

从多个线程访问对象

MFC 对象本身不是线程安全的。 除非你使用 MFC 同步类和/或适当的 Win32 同步对象(如临界区),否则两个单独的线程无法操作同一对象。 有关临界区和其他相关对象的详细信息,请参阅 Windows SDK 中的同步

类库在内部使用临界区来保护全局数据结构,例如调试内存分配所使用的临界区。

从非 MFC 线程访问 MFC 对象

如果你有一个多线程应用程序,它创建线程的方式不是使用 CWinThread 对象,则你无法从该线程访问其他 MFC 对象。 换句话说,若要从辅助线程访问任何 MFC 对象,则必须使用多线程:创建用户界面线程多线程:创建工作线程中所述的方法之一创建该线程。 这些方法是唯一允许类库初始化那些处理多线程应用程序所需的内部变量的方法。

Windows 句柄映射

一般说来,线程只能访问其创建的 MFC 对象。 这是因为临时的和永久的 Windows 句柄映射保存在线程本地存储中,目的是阻止从多个线程同时进行的访问。 例如,工作线程无法在执行计算后调用文档的 UpdateAllViews 成员函数来修改包含有关新数据的视图的窗口。 这完全不起作用,因为从 CWnd 对象到 HWND 的映射是主线程的本地映射。 这意味着一个线程可能有从 Windows 句柄到 C++ 对象的映射,但另一个线程可能会将该句柄映射到不同的 C++ 对象。 在一个线程中所做的更改不会反映在另一个线程中。

有几种方法可以避免此问题。 第一种是将单个句柄(例如 HWND)而不是 C++ 对象传递给工作线程。 然后,工作线程通过调用相应的 FromHandle 成员函数将这些对象添加到其临时映射中。 还可以通过调用 Attach 将对象添加到线程的永久映射中,但只能在确保对象存在的时间超过线程存在的时间时执行此操作。

另一种方法是创建新的用户定义消息(这些消息对应于将由工作线程执行的不同任务),并使用 ::PostMessage 将这些消息发布到应用程序的主窗口。 这种通信方法类似于两个不同的应用程序进行会话,但两个线程都在相同的地址空间中执行。

有关句柄映射的详细信息,请参阅技术说明 3。 有关线程本地存储的详细信息,请参阅 Windows SDK 中的线程本地存储使用线程本地存储

在线程之间通信

MFC 提供了许多类,这些类允许线程同步对对象的访问,以维护线程安全性。 多线程处理:如何使用同步类多线程处理:何时使用同步类中介绍了这些类的用法。 有关这些对象的详细信息,请参阅 Windows SDK 中的同步

另请参阅

使用 C++ 和 MFC 进行多线程编程