窗口和线程漫谈

为什么要讨论窗口和线程

讨论这个依然是跟之前的项目经历有关。这里暂且称该项目为 A 项目。A 项目包括一个客户端和服务端,客户端有一个核心的网络模块,该网络模块基于完成端口开发,有多个工作线程,网络模块负责接收来自服务端的数据,对这些数据进行处理,并将最终的处理结果显示在窗口上。那么问题来了,工作线程如何将数据的最终处理结果显示在窗口上?可以说这个问题不仅仅是 A 项目中遇到的问题,绝大多数网络应用程序都会遇到这个问题。当时 A 项目中采用的方案是在工作线程中利用窗口句柄直接调用相应函数(如 SendMessage)对窗口进行操作。虽然这种做法当时并没有出现问题?但它真的没问题吗?如果有问题,我们该采用什么方式将最终的处理结果显示在窗口上呢?

窗口和线程的关系

理论知识是我们回答上述问题的基础。这方面我找到的唯一资料就是 《Windows 核心编程》 第 26 章 窗口消息。对这块不太明白的兄弟,可以先看下。这里我们就不详述了。

在工作线程中利用窗口句柄直接调用相应函数对窗口进行操作这种做法有没有问题

绝大多数情况下,确实不会出现问题。但只是绝大多数情况下,下面是出现问题的两种情况。

  1. 这种情况是我在项目 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 章 中的相关描述,每一个线程都拥有自己的键盘焦点,应该在一定程度上回答了这个问题。

  2. 这种情况是《多线程编程中的主界面安全处理》这篇文章中提到的,大致情况就是拥有窗口的线程正在等待工作线程退出,而工作线程正阻塞于对窗口的 SendMessage 调用中。应该说,这种情况不是没有可能发生。

说了这么多,说到底我是不建议在工作线程中利用窗口句柄直接调用相关函数对窗口进程操作这种做法的,虽然这种做法绝大多数情况下不会出错,但一旦出现问题,排查起来就比较困难。但我也不完全否认这种做法,前提是,程序员自身一定要对程序本身的逻辑认识清楚,比如在工作线程中会不会调用类似 SetFocus 的这类函数,会不会出现上面提到的第二种情况。

工作线程如何将最终的处理结果显示到窗口

既然,在工作线程中通过窗口句柄直接调用相关函数对窗口进行操作的这种做法不太好,那采用什么方法将最终的处理结果显示到窗口上呢?我的方法是调用 PostMessage,通过自定义消息将数据交给窗口的窗口过程处理,也就是拥有窗口的线程处理,这种情况下工作线程中唯一和窗口相关的操作就是通过窗口句柄调用 PostMessage。目前,我并想不到这种做法有什么有问题的地方,如果有人觉得有问题,大家可以一起讨论下。

另外,如果有兄弟知道更好的做法,大家也可以讨论下。

感受和思考

在查找线程和窗口的相关资料过程中,发现很多人都在问关于线程和窗口的一些问题,在讨论关于窗口和线程的一些概念,而且搞出来一些很玄乎的东西。但其实搞清楚一些基础知识,自己独立思考一下,这些问题并不难回答。也许 MFC 相对传统的 Win32 API 确实方便些,但窗口过程,消息循环等一些基本概念还是要理解的。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-03 14:45:08

窗口和线程漫谈的相关文章

窗体和线程漫谈之工作线程怎样将数据的处理结果显示到窗体

前言 原本这篇博客的标题叫<窗体和线程漫谈>,但想来想去确实不太合适.由于我确实没有写关于窗体和线程的不论什么理论知识,而仅仅是探讨了工作线程怎样将数据的处理结果显示到窗体这个问题,因此又一次改动标题. 另外,关于窗体和线程的相关理论知识.感觉一两句话确实说不清楚,并且<Windows 核心编程>这本书上介绍的也挺好的.有机会再写吧.特别是感觉如今好多人都直接在学 MFC,用 MFC.甚至连窗体过程,消息循环都不太明确,假设能有这样一篇博客也是非常有价值的. 为什么要讨论这个问题

windows 消息循环和窗口与线程关系

/WinMain函数 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ g_hinstance = hInstance; if( !Register("Main",WndProc) ) //注册窗口类 RegisterClassEx { MessageBox(NULL,"注册失败","Infor",M

Windows线程漫谈界面线程和工作者线程

每个系统都有线程,而线程的最重要的作用就是并行处理,提高软件的并发率.针对界面来说,还能提高界面的响应力. 线程分为界面线程和工作者线程,界面实际就是一个线程画出来的东西,这个线程维护一个“消息队列”,“消息队列”也是界面线程和工作者线程的最大区别,这个词应该进到你的脑子里,根深蒂固的! 如果在界面线程的某个地方停住,这说明它处理不了窗口消息了,所以有时候我们就会看到整个界面无响应了.这种问题后面会提供一个叫 WaitForObjectEx 的函数来解决,我们后面再谈. 线程首先就是它的创建,创

用Java runnable接口模拟多窗口(线程)销售同类型票的并行程序

参考了此篇博文(http://blog.csdn.net/liutengteng130/article/details/20036517),其中,就使用thread和runnable接口实现售票多窗口模拟问题. 就runnable接口实现方法的特性--多线程无差错修改类公共变量值问题,觉得很有价值,对源代码做了批注,拿来分析下和大家共享: class ThreadTest implements Runnable{ private int ticket =100; //100张票需要销售 publ

windows 窗口过程 线程消息队列

message loop window procedure message loop: a for loop in thread or winmain  GetMessage, TranslateMessage, and DispatchMessage GetMessage: get the message DispatchMessage: Dispatches a message to a window procedure. ----- winproc WindowProc callback

在C#中子线程如何操作主窗口线程上的控件

在C#中子线程怎样操作主线程中窗口上控件 在C#中,直接在子线程中对窗口上的控件操作是会出现异常,这是因为子线程和运行窗口的线程是不同的空间,因此想要在子线程来操作窗口上的控件.是不可能简单的通过控件对象名来操作,但不是说不能进行操作,微软提供了Invoke的方法.其作用就是让子线程告诉窗口线程来完毕对应的控件操作. 要实现该功能,基本思路例如以下: 把想对还有一线程中的控件实施的操作放到一个函数中,然后使用delegate代理那个函数.而且在那个函数中加入一个推断,用 InvokeRequir

该函数设置由不同线程产生的窗口的显示状态。

using System;using System.Collections.Generic;using System.Linq;using System.Windows.Forms;using System.Runtime.InteropServices;using System.Diagnostics;using System.Reflection; namespace WindowsFormsApplication1{ static class Program { /// <summary>

眼见为实(2):介绍Windows的窗口、消息、子类化和超类化

眼见为实(2):介绍Windows的窗口.消息.子类化和超类化 这篇文章本来只是想介绍一下子类化和超类化这两个比较"生僻"的名词.为了叙述的完整性而讨论了Windows的窗口和消息,也简要讨论了进程和线程.子类化(Subclassing)和超类化(Superclassing)是伴随Windows窗口机制而产生的两个复用代码的方法.不要把"子类化.超类化"与面向对象语言中的派生类.基类混淆起来."子类化.超类化"中的"类"是指W

window窗口详解

窗口 在图形化的基于win32的应用程序,窗口是屏幕的矩形区域,应用程序显示输出并接收来自用户的输入,因此,一个图形化基于win32的应用程序的首要任务之一就是创建一个窗口. 窗口与其它窗口共享屏幕,[本事]包括来自其它应用程序的窗口,每次只有一个窗口可以接收来自用户的输入,用户可以使用鼠标.键盘或其它输入设备与此窗口以及拥有该窗口的应用程序进行交互. 关于窗口 这个概述描述了应用程序用来创建和使用窗口的编程单元:管理窗口之间的关系:以及大小.移动.和显示窗口:概述包括以下主题: 桌面窗口