嗯,事实上 MFC 的封装不是这么好用啊。诸如因为我先是了解过安卓,然后再来看 MFC,就觉得 MFC 实在是有点猥琐。线程间的通信,似乎比较简单而强大的方式就是利用 Message 的方式,就如同 Android 中的 Hhandler 一样。

CWinThread

对于我们的每一个 MFC 程序来说,都会有一个主线程,和主进程。这两者,是有操作系统来针对每个程序来建立的。通常,我们的主线程会运行在一个从 CWinApp 继承的类中。

大体上可以将 MFC 的线程分为两类:工作线程与 UI 线程,两者的区别就在于是否处理消息。当然,CWinThread 本身都有一个消息队列,而有没有一个消息循环来处理这个队列,就决定了其到底是一个工作线程还是 UI 线程。

如安卓那样,事实上我更愿意将所有的 UI 操作都放在一个线程(主线程),而将其他的文件相关,网络相关的操作都放到另外一个线程,这势必就涉及到线程间如何通信的问题。

通常, CWinThread 实例的生命周期和其创造的线程是一致的,但我们可以通过设置 m_bAutoDeleteFALSE 来改变这一行为。

我们可以通过 AfxBeginThread() 方法来建立线程。如果我们想要建立的是一个 UI 线程,那么需要传递给这个函数一个继承自 CWinThread 类的 CRutimeClass。

当然我们其实也可以通过一个两步操作来建立线程,这在需要复用 CWinThread 对象的时候就很有用了:

  1. 建立 CWinThread 对象。
  2. 调用其 CreateThread 方法。

AfxBeginThread

CWinThread* AfxBeginThread(
AFX_THREADPROC pfnThreadProc,
LPVOID pParam,
int nPriority = THREAD_PRIORITY_NORMAL,
UINT nStackSize = 0,
DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);

CWinThread* AfxBeginThread(
CRuntimeClass* pThreadClass,
int nPriority = THREAD_PRIORITY_NORMAL,
UINT nStackSize = 0,
DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);

这两种形式, 主要的区别就是一个接受一个 CRuntimeClass 也就是我们的继承类类型作为参数,一个直接就将函数作为参数了。

例子

我们就以多个线程不停的获取当前时间,然后显示到我们的对话框为例来进行展示。

线程间通信

通常,我们多个线程之间是需要通信的,比如对于多个线程计算后的结果我需要在主线程(UI线程上最终显示出来),这个时候我们怎么来处理这些个问题。

前面的内容我们已经知道, CWinThread 其实是有消息队列的,同时如果处理 UI 消息的话还会有消息循环,所以我们可以完全以传递消息的形式来进行通信。但我也忍不住会想,那对于没有处理窗口信息的线程又该怎么办呢。

事实上这也是可以的。