[备忘]不用许可证 多线程直接操作界面组件比如超级列表框的实现

平时多线程来操作界面组件 同时写入或者修改数据  比如常见的把多个线程都把日志同时写入到编辑框 又或者 多个线程同时的修改一个超级列表框上的线程状态和其他信息 这样会出现一个问题 如何避免多个线程同时操作一个组件导致的组件冲突问题 我们常用的是使用许可证来给每个线程规定访问顺序来依次执行 不过这样的调整的确从效率上说很低下

大漠老师使用 发送消息 或者说是使用window消息机制来实现不加许可证的同时修改界面组件的思路非常好

511遇见老师也对这个思路进行了深度解析 已经非常的详细了http://www.511yj.com/eyuyan-dthread-31.html

这个方式的情况

优点

(1)不需要加许可证 效率比许可证明显提高

(2)就算使用了许可证 多线程下在对不是在本线程内创建的com对象或者组件进行操作 依然会存在崩溃的可能性 而这个方法能够彻底的避免这个情况 所以它基本上是唯一的选择 许可证辅助 因为我们操作组件 其实只是触发了组件的某个指定事件 这事件的处理依然还是在主线程里面发生的 而不是在多线程里面 或者说是发生在界面上的某个组件的事件里面 这样就符合了 哪个线程创建的com对象或者组件就在哪个线程里面处理的原则

缺点

(1)需要对window消息机制有点了解 起码对要用到的3个系统API的功能和使用方法有一定了解

(2)如果间隔太短 或者过于频繁的写入 依然会造成界面陷入短暂卡死的情况 我建立了20个线程 每个线程以间隔10毫秒的方式对一个超级列表框进行修改对应的记录信息 结果就是时常陷入假死 但是没有真正彻底卡死  把线程内间隔10毫秒改为100毫秒 基本就看不到卡死的情况



小知识:个人理解下的全局变量的类型选择偏向

如果可能 尽量选择一些数值类型 或者逻辑类的全局变量 ,一些文本型的全局变量 在被多线程使用的时候可能存在一些极端情况 因为数值类型或者逻辑型的 在内存中占据的空间是固定大小的 而文本型却是根据内容多寡而在内存占据的空间会变化的  比如目前a这个全局变量的内容占据16个字节 1号线程访问按照16字节的大小读取 但是可能在这瞬间 因为全局变量的读取并没有许可证一类的机制 所以可能在访问的一时间 2号线程已经把a这个全局变量的内容改变了 现在占据8个字节 那么这个时候1号线程依然按照16字节读取 就会造成线程冲突导致崩溃

结论:如果可能 全局变量尽量选择一些内容长度固定的变量类型来实现



个人理解的发送消息访问组件的基本原理

首先要对window消息机制有点了解 我们平时 比如窗口载入事件  窗口销毁事件 按钮点击事件 这些东西都是属于window消息机制  系统一直在维护一个window消息列表  每当我们操作触发了一个窗口事件 会自动把该事件的消息加入这个window消息列表 ,然后系统一直在从上到下依次一个个的执行列表里面的项 根据传递的事件的信息 来决定用什么函数来执行这个事件。但是我们可以通过3个系统API  可以改写指定的某个事件对应的系统默认的处理函数  我们可以把这个默认处理函数修改为我们自己写的函数 每次触发了指定事件后  处理方式是按照我们的指定函数来执行而不是系统默认的处理函数 因为触发的事件是系统读取window消息列表自动从上到下依次执行 不会产生冲突 自动解决了多线程同时操作导致的问题


需要用到的系统API(可以直接从易语言助手里面找到对应的)

.版本 2

.DLL命令 CallWindowProcA, 整数型, "user32.dll", "CallWindowProcA", , 呼叫窗口函数地址
    .参数 lpPrevWndFunc, 整数型, , 前一窗口函数地址
    .参数 hWnd, 整数型, , 窗口句柄
    .参数 Msg, 整数型, , 消息值
    .参数 wParam, 整数型, , 附加参数1
    .参数 lParam, 整数型, , 附加参数2

.DLL命令 SetWindowLongA, 整数型, "user32.dll", "SetWindowLongA", , 改变指定窗口的属性,函数也将指定的一个32位值设置在窗口的额外存储空间的指定偏移位置。
    .参数 hWnd, 整数型, , 窗口句柄及间接给出的窗口所属的类。
    .参数 nIndex, 整数型, , 指定将设定的大于等于0的偏移值。
    .参数 dwNewLong, 整数型, , 指定的替换值。

.DLL命令 GetWindowLongA, 长整数型, "user32.dll", "GetWindowLongA", , 获得有关指定窗口的信息,函数也获得在额外窗口内存中指定偏移位地址的32位度整型值
    .参数 hWnd, 整数型, , 窗口句柄及间接给出的窗口所属的窗口类。
    .参数 nIndex, 整数型, , 指定要获得值的大于等于0的值的偏移量。

GetWindowLongA 是用来获取某个窗口句柄的所有事件对应的系统默认的处理函数的入口地址

SetWindowLongA用用来设置某个窗口句柄的所有事件对应的我们自己定义的处理函数

CallWindowProcA 是用来单独运行某个窗口句柄的所有事件对应的系统默认的处理函数

基本用法

1.设置2个全局变量来获取当前窗口句柄(窗口句柄)和当前窗口句柄的所有事件对应的系统默认处理函数的入口地址(窗口过程

2 通过3个API 把系统默认的当前窗口的所有事件对应的处理函数变为我们自己的处理函数,并且这个改变必须在主线程里面 不能再其他线程里 那样是无效的 一般都是放在UI载入事件里面

.版本 2
.支持库 iext

.子程序 __启动窗口_创建完毕

日志_初始化 ()
窗口句柄 = _启动窗口.取窗口句柄 ()
窗口过程 = GetWindowLongA (窗口句柄, -4)
SetWindowLongA (窗口句柄, -4, 到数值 (&WindowProc))

.子程序 WindowProc, 整数型
.参数 hwnd, 整数型
.参数 msg, 整数型
.参数 wparam, 整数型
.参数 lparam, 整数型

.如果真 (msg = 1666)
    ‘ 调试输出 (“[” + 到文本 (msg) + “]-[” + 到文本 (wparam) + “]-[” + 到文本 (lparam) + “]”)
    _启动窗口.超级列表框1.置标题 (wparam - 1, 0, 到文本 (大漠多线程数组 [wparam].id))
    _启动窗口.超级列表框1.置标题 (wparam - 1, 1, 大漠多线程数组 [wparam].name)
    _启动窗口.超级列表框1.置标题 (wparam - 1, 2, 到文本 (大漠多线程数组 [wparam].age))
    _启动窗口.超级列表框1.置标题 (wparam - 1, 3, 大漠多线程数组 [wparam].address)
    _启动窗口.超级列表框1.置标题 (wparam - 1, 4, 大漠多线程数组 [wparam].备注)
.如果真结束
返回 (CallWindowProcA (窗口过程, hwnd, msg, wparam, lparam))

3.就是每个线程都使用 发送消息函数来触发把全局线程数组的内容写入到超级列表框对应的记录里面 其中 发送消息第一个参数 只要是超出1024的都属于自定义事件 可以随便选择 我这里选了一个1666  第二个和第三个参数其实是随意的 我这里就是第二个参数来存储 大漠多线程数组的标识 也是线程的标识 第三个是操作模式 是要把大漠多线程数组内容更新到超级列表框还是把超级列表框对应记录的内容全部重置或者是其他的操作 等等

.版本 2

.子程序 线程_主线程
.参数 大漠多线程数组标识, 整数型
.局部变量 i, 整数型

线程_初始化COM库 ()
置随机数种子 ()

.计次循环首 (1000000, i)
    大漠多线程数组 [大漠多线程数组标识].id = 取随机数 (1, 100)
    大漠多线程数组 [大漠多线程数组标识].name = 文本_取随机汉字 (3)
    大漠多线程数组 [大漠多线程数组标识].age = 取随机数 (1, 100)
    大漠多线程数组 [大漠多线程数组标识].address = 文本_取随机汉字 (5)
    大漠多线程数组 [大漠多线程数组标识].备注 = 文本_取随机汉字 (10)

    _启动窗口.发送信息 (1666, 大漠多线程数组标识, 0)  ‘ 第一个参数固定为1666  第二个是 第三个是操作模式 0是更新 1还是清空
    辅助延时 (100)
.计次循环尾 ()
线程_取消COM库 ()

123

原文地址:https://www.cnblogs.com/zjl8455482/p/10743580.html

时间: 2024-10-30 16:58:25

[备忘]不用许可证 多线程直接操作界面组件比如超级列表框的实现的相关文章

第84课 多线程与界面组件的通信(上)

1. 有趣的问题: [编程实验]是否可以在子线程中创建界面组件 //TestThread.h #ifndef TESTTHREAD_H #define TESTTHREAD_H #include <QThread> class TestThread : public QThread { Q_OBJECT protected: void run(); public: explicit TestThread(QObject* parent = 0); }; #endif // TESTTHREAD

JqGrid相关操作备忘 方法列表

JqGrid相关操作备忘 方法列表 1.获得当前列表行数:$("#gridid").getGridParam("reccount"); 2.获取选中行数据(json):$("#gridid").jqGrid('getRowData', id); 3.刷新列表:$(refreshSelector).jqGrid('setGridParam', { url: ''), postData: ''}).trigger('reloadGrid'); 4.选

jdbc中对mysql数据库操作的简单封装--(仅做备忘记录)

本次使用jdbc中的mysql-connector-java-5.1.47-bin.jar的连接包,下载这个jar包放在javaee项目的WEB-INF/lib目录下,再把它作为外包jar包进入到libraries中,这样就可以使用mysql的jdbc接口了. 自己封装的代码中引入了两个自己字义的Exception:SqlSecureException.java package com.myproweb.exception; public class SqlSecureException ext

MySQL使用备忘的实际操作步骤概述

以下的文章主要向大家介绍的是MySQL使用备忘的实际操作步骤,随着MySQL数据库的广泛应用随之MySQL相关的实际应用也越来越受重视,以下就是文章的具体内容描述,望你能有所收获. 使MySQL写日志 编辑my.ini [MySQLd] log MySQL用limit分页 select * from tablename limit offset,rowcount,offset从0开始,rowcount是返回的条数 忘记密码 1.用任务管理器kill掉MySQL进程 2.执行MySQLd --sk

mysql 常用命令(备忘)

1:使用SHOW语句找出在服务器上当前存在什么数据库:mysql> SHOW DATABASES; 2:2.创建一个数据库MYSQLDATAmysql> CREATE DATABASE MYSQLDATA;3:选择你所创建的数据库 mysql> USE MYSQLDATA; (按回车键出现Database changed 时说明操作成功!) 4:查看现在的数据库中存在什么表mysql> SHOW TABLES;5:创建一个数据库表mysql> CREATE TABLE MYT

linux下常用命令备忘

转自:Linux 命令集锦 linux下查看监听端口对应的进程 # lsof -i:9000 # lsof -Pnl +M -i4 如果退格键变成了:"^h". 终端连接unix删除退格键,按住CTL键同时按delete Linux搜索 # find / -name "xxx.conf" 查看linux是32位还是64位的命令 #file /sbin/init #getconf LONG_BIT #getconf -a 在Linux和Windows下都可以用nslo

Cheat—— 给Linux初学者和管理员一个终极命令行&quot;备忘单&quot;

编译自:http://www.tecmint.com/cheat-command-line-cheat-sheet-for-linux-users/作者: Avishek Kumar原创:LCTT https://linux.cn/article-3760-1.html译者: su-kaiyao原文稍有改动 当你不确定你所运行的命令,尤其是那些使用了许多选项的复杂命令时,你会怎么做?在这种情况下,我们使用man pages来获取帮助.还有一些其它的选择可能包括像‘help’,‘whereis’和

Objective-C教程备忘单

终极版本的Objective-C教程备忘单帮助你进行iOS开发. 想开始创建你的第一个iOS应用程序么?那么看一下这篇很棒的教程吧:Create your first iOS 7 Hello World Application 注:这篇文章我写了三天,可能在一些必要的地方使用了编辑和说明,所以如果有任何疑问和修改建议请在下方评论. 这不是一个初学者指南,也不是关于Objective-C的详细讨论,这是关于常见的和高水平的论题的快速索引. 如果这里有些问题没有涉及到,你也可以查阅以下文章: Obj

Oracle数据库手动恢复备忘日志

最近因为升级了Mac os x 10.10 Yosemite,突然前几天的一个晚上,开机发现就停留在开机界面了,看来BETA果然是不靠谱,然后想到自己这不前几天刚备份完吗,没事,TimeMachine是何等神器,二话不说直接恢复.但是恢复完,我后悔了,一来是忘了昨天晚上还加班呢,加班的成功保留成果所剩无几,关键我这才发现TimeMachine既然不备份虚拟机文件(虚拟机文件30G,估计直接给略过了吧),难怪每次都觉得备份那么快. 不过后悔也没用,重新搭开发环境吧.操作系统WIN7->开发工具VS