为什么要讨论窗口和线程
讨论这个依然是跟之前的项目经历有关。这里暂且称该项目为 A 项目。A 项目包括一个客户端和服务端,客户端有一个核心的网络模块,该网络模块基于完成端口开发,有多个工作线程,网络模块负责接收来自服务端的数据,对这些数据进行处理,并将最终的处理结果显示在窗口上。那么问题来了,工作线程如何将数据的最终处理结果显示在窗口上?可以说这个问题不仅仅是 A 项目中遇到的问题,绝大多数网络应用程序都会遇到这个问题。当时 A 项目中采用的方案是在工作线程中利用窗口句柄直接调用相应函数(如 SendMessage)对窗口进行操作。虽然这种做法当时并没有出现问题?但它真的没问题吗?如果有问题,我们该采用什么方式将最终的处理结果显示在窗口上呢?
窗口和线程的关系
理论知识是我们回答上述问题的基础。这方面我找到的唯一资料就是 《Windows 核心编程》 第 26 章 窗口消息。对这块不太明白的兄弟,可以先看下。这里我们就不详述了。
在工作线程中利用窗口句柄直接调用相应函数对窗口进行操作这种做法有没有问题
绝大多数情况下,确实不会出现问题。但只是绝大多数情况下,下面是出现问题的两种情况。
- 这种情况是我在项目 A 中亲身经历的。当时我在工作线程中调用了 SetFocus 这个函数,结果这个函数并没有成功返回,为什么?下面是 SetFocus 文档中的描述。
Sets the keyboard focus to the specified window. The window must be attached to the calling thread’s message queue.
原因很明显,传递给 SetFocus 函数的窗口句柄代表的窗口必须是属于调用 SetFocus 函数的这个线程的,但工作线程并没拥有该窗口,也没有拥有任何窗口。那为什么调用 SetFoucs 函数要有这个需求呢?这个只能说我也不太清楚,但结合 《Windows 核心编程》 第 26 章 中的相关描述,每一个线程都拥有自己的键盘焦点,应该在一定程度上回答了这个问题。
- 这种情况是《多线程编程中的主界面安全处理》这篇文章中提到的,大致情况就是拥有窗口的线程正在等待工作线程退出,而工作线程正阻塞于对窗口的 SendMessage 调用中。应该说,这种情况不是没有可能发生。
说了这么多,说到底我是不建议在工作线程中利用窗口句柄直接调用相关函数对窗口进程操作这种做法的,虽然这种做法绝大多数情况下不会出错,但一旦出现问题,排查起来就比较困难。但我也不完全否认这种做法,前提是,程序员自身一定要对程序本身的逻辑认识清楚,比如在工作线程中会不会调用类似 SetFocus 的这类函数,会不会出现上面提到的第二种情况。
工作线程如何将最终的处理结果显示到窗口
既然,在工作线程中通过窗口句柄直接调用相关函数对窗口进行操作的这种做法不太好,那采用什么方法将最终的处理结果显示到窗口上呢?我的方法是调用 PostMessage,通过自定义消息将数据交给窗口的窗口过程处理,也就是拥有窗口的线程处理,这种情况下工作线程中唯一和窗口相关的操作就是通过窗口句柄调用 PostMessage。目前,我并想不到这种做法有什么有问题的地方,如果有人觉得有问题,大家可以一起讨论下。
另外,如果有兄弟知道更好的做法,大家也可以讨论下。
感受和思考
在查找线程和窗口的相关资料过程中,发现很多人都在问关于线程和窗口的一些问题,在讨论关于窗口和线程的一些概念,而且搞出来一些很玄乎的东西。但其实搞清楚一些基础知识,自己独立思考一下,这些问题并不难回答。也许 MFC 相对传统的 Win32 API 确实方便些,但窗口过程,消息循环等一些基本概念还是要理解的。
版权声明:本文为博主原创文章,未经博主允许不得转载。