VC多线程--在线程之间传递窗口句柄是安全的

2024-06-08 03:08

本文主要是介绍VC多线程--在线程之间传递窗口句柄是安全的,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

总结:使用MFC编写多线程应用程序,不能跨线程传递MFC对象。

解决的方法是使用窗口句柄而不是MFC对象。在线程之间传递窗口句柄是安全的。如果线程A向线程B传递一个窗口句柄,那么,线程B可以通过发送消息给拥有该句柄的窗口对象。在处理窗口消息时,系统已经切换到线程A。这是验证窗口对象的有效性会成功。


Description of CWnd derived MFC objects and multithreaded applications in Visual C++
http://support.microsoft.com/default.aspx?scid=kb;en-us;147578
VC++中CWnd及其子类和多线程应用程序的描述

SUMMARY
In a multi-threaded application written using MFC, you should not pass MFC objects across thread boundaries. As a general rule, a thread should access only those MFC objects that it creates. Failure to do so may cause run-time problems including assertions or unexpected program behavior.
使用MFC编写多线程应用程序,不能跨线程传递MFC对象。作为一种基本的准则,线程只允许操作由其本身创建的MFC对象。不遵守该准则将导致断言(assertion)或者无法预知的程序行为等运行期错误。

MORE INFORMATION
In a Win32 process, all the threads running in the process address space can view all global and static data. A thread can use thread-local-storage (TLS) to store any thread-specific data. 
所有运行在win32进程地址空间中的线程能够查看全局和静态的数据。线程使用“线程局部存储(TLS)”技术来存储跟线程相关的数据。

In a multi-threaded environment because windows are owned by threads, MFC keeps the temporary and permanent window handle map in thread local storage. The same is true for other handle maps like those for GDI objects and device contexts. Keeping the window handle maps in thread local storage ensures protection against simultaneous access by several threads. 
在多线程环境中,由于所有的窗口元素都通过线程来管理,于是MFC将暂时/永久窗口<->句柄映射保存在TLS中。其他的窗口句柄映射以及设备描述表也是采用类似的方法存储。将这些窗口句柄映射存储在TLS中能够防止其他线程同时访问这些数据。

The behavior of the functions CHandleMap::LookupPermanent() and CHandleMap::LookupTemporary() is a direct consequence of these facts. Given a window handle, these functions check the permanent and temporary window handle maps of the current thread for the existence of an associated CWnd derived MFC object. This means that if calls to these functions are made from a thread to search for MFC objects that represent windows created in other threads, these calls will fail. 
函数:CHandleMap::LookupPermanent() 和 CHandleMap::LookupTemporary()就是这种理论的直接产物。给定窗口句柄,这些函数通过查找临时以及永久的窗口句柄映射来获得CWnd或者其子类对象。这就意味着如果一个线程调用这些函数来查找其他线程的CWnd或者其子类对象,调用将失败。

There are several functions that call CHandleMap::LookupPermanent() and CHandleMap::LookupTemporary(). CWnd::AssertValid() (and hence the macro ASSERT_VALID for a CWnd object) is one such function. This function is called to make validity checks on an object. If AssertValid() fails to find an entry for the MFC object's m_hWnd member in any of the handle maps or finds an incorrect entry, it fires an assertion. In Visual C++ 2.1, these assertions are in file Wincore.cpp, lines 797 and 798. In Visual C++ 2.2, they are in Wincore.cpp, lines 804 and 805. In Visual C++ 4.0, they are in Wincore.cpp, lines 871 and 872. 
MFC中有大量函数调用CHandleMap::LookupPermanent() and CHandleMap::LookupTemporary()。CWnd::AssertValid()就是其中一个(宏ASSERT_VALID也是一个).调用该函数来检查对象的有效性。如果没有发现有效的CWnd对象,则会报“断言(Assertion)”错误。VC2.1中,该错误出现在wincore.cpp, lines 797 & 798, VC2.2中,出现在wincore.cpp行804和805,VC4.0则出现在行871和872。
Calls to the ASSERT_VALID macro are sprinkled all over the MFC source code. Hence, from a particular thread, if you end up calling a function that calls ASSERT_VALID on MFC window objects that belong to some other thread, you get an assertion. If you do not get an assertion, you may still get abnormal behavior because you are not allowed to directly manipulate windows created by other threads. 
宏ASSERT_VALID的调用在MFC中相当频繁。这样,如果你调用该宏来验证其他线程对象的有效性,就会出现断言错误。就算不出现断言错误,也会导致程序异常退出,这是因为不允许直接操作其他线程中的CWnd对象。

The correct approach in such situations is to work with window handles, not MFC objects. It is safe to pass window handles across thread boundaries. If thread A passes a window handle to thread B, then thread B can use this window handle to send or post messages to the window. When these messages are processed, you are back in the context of thread A and calls to CWnd::AssertValid() to check thread A's window handle maps will succeed. 
解决的方法是使用窗口句柄而不是MFC对象。在线程之间传递窗口句柄是安全的。如果线程A向线程B传递一个窗口句柄,那么,线程B可以通过发送消息给拥有该句柄的窗口对象。在处理窗口消息时,系统已经切换到线程A。这是验证窗口对象的有效性会成功。

In this scenario, thread B can also use the CWnd::FromHandle() function to get a temporary CWnd object which is placed in thread B's temporary handle map. However this object may be of only limited use, because in no way is it in synchronization with the MFC object existing in thread A's handle maps. 

与此同时,线程B能够调用CWnd::FromHandle()函数来获得暂时的窗口对象,不过这一对象应该谨慎使用。因为它无法与存在于线程A窗口对象映射中的对象同步。


这篇关于VC多线程--在线程之间传递窗口句柄是安全的的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1041057

相关文章

Vue中组件之间传值的六种方式(完整版)

《Vue中组件之间传值的六种方式(完整版)》组件是vue.js最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用,针对不同的使用场景,如何选择行之有效的通信方式... 目录前言方法一、props/$emit1.父组件向子组件传值2.子组件向父组件传值(通过事件形式)方

Java使用多线程处理未知任务数的方案介绍

《Java使用多线程处理未知任务数的方案介绍》这篇文章主要为大家详细介绍了Java如何使用多线程实现处理未知任务数,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 知道任务个数,你可以定义好线程数规则,生成线程数去跑代码说明:1.虚拟线程池:使用 Executors.newVir

MySQL使用binlog2sql工具实现在线恢复数据功能

《MySQL使用binlog2sql工具实现在线恢复数据功能》binlog2sql是大众点评开源的一款用于解析MySQLbinlog的工具,根据不同选项,可以得到原始SQL、回滚SQL等,下面我们就来... 目录背景目标步骤准备工作恢复数据结果验证结论背景生产数据库执行 SQL 脚本,一般会经过正规的审批

最新Spring Security实战教程之Spring Security安全框架指南

《最新SpringSecurity实战教程之SpringSecurity安全框架指南》SpringSecurity是Spring生态系统中的核心组件,提供认证、授权和防护机制,以保护应用免受各种安... 目录前言什么是Spring Security?同类框架对比Spring Security典型应用场景传统

Python实现PDF与多种图片格式之间互转(PNG, JPG, BMP, EMF, SVG)

《Python实现PDF与多种图片格式之间互转(PNG,JPG,BMP,EMF,SVG)》PDF和图片是我们日常生活和工作中常用的文件格式,有时候,我们可能需要将PDF和图片进行格式互转来满足... 目录一、介绍二、安装python库三、Python实现多种图片格式转PDF1、单张图片转换为PDF2、多张图

JAVA封装多线程实现的方式及原理

《JAVA封装多线程实现的方式及原理》:本文主要介绍Java中封装多线程的原理和常见方式,通过封装可以简化多线程的使用,提高安全性,并增强代码的可维护性和可扩展性,需要的朋友可以参考下... 目录前言一、封装的目标二、常见的封装方式及原理总结前言在 Java 中,封装多线程的原理主要围绕着将多线程相关的操

Java对象和JSON字符串之间的转换方法(全网最清晰)

《Java对象和JSON字符串之间的转换方法(全网最清晰)》:本文主要介绍如何在Java中使用Jackson库将对象转换为JSON字符串,并提供了一个简单的工具类示例,该工具类支持基本的转换功能,... 目录前言1. 引入 Jackson 依赖2. 创建 jsON 工具类3. 使用示例转换 Java 对象为

Python中多线程和多进程的基本用法详解

《Python中多线程和多进程的基本用法详解》这篇文章介绍了Python中多线程和多进程的相关知识,包括并发编程的优势,多线程和多进程的概念、适用场景、示例代码,线程池和进程池的使用,以及如何选择合适... 目录引言一、并发编程的主要优势二、python的多线程(Threading)1. 什么是多线程?2.

SpringBoot中使用 ThreadLocal 进行多线程上下文管理及注意事项小结

《SpringBoot中使用ThreadLocal进行多线程上下文管理及注意事项小结》本文详细介绍了ThreadLocal的原理、使用场景和示例代码,并在SpringBoot中使用ThreadLo... 目录前言技术积累1.什么是 ThreadLocal2. ThreadLocal 的原理2.1 线程隔离2

Java多线程父线程向子线程传值问题及解决

《Java多线程父线程向子线程传值问题及解决》文章总结了5种解决父子之间数据传递困扰的解决方案,包括ThreadLocal+TaskDecorator、UserUtils、CustomTaskDeco... 目录1 背景2 ThreadLocal+TaskDecorator3 RequestContextH