找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 6170|回复: 0

[教程源码] [转载][361度]多线程与变量

[复制链接]
  • 打卡等级:行侠仗义

1080

主题

2100

回帖

4280

积分

院长

鲜花
6
猫粮
7394
QQ
发表于 2018-10-11 19:38:07 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

这里先说主线程和子线程,对按键精灵脚本来说,启动脚本直接运行的脚本线程是主线程,由脚本中BeginThread创建的线程序是子线程序,主线程是它们的父线程。


按键键精灵脚本的变量有四种:脚本全局变量、局部变量(Dim)、环境变量(DimEnv)、按键精灵全局变量(Global)。按键精灵有两种变量都叫全局变量,名称冲突了,所以这里将他们分别命名为脚本全局变量和按键精灵全局变量。按键精灵脚本的语言叫Q语言,是从vbs语言中扩展出来的。脚本全局变量是vbs语言中本来就有的,所以叫脚本全局变量。按键精灵全局变量是按键精灵的Q语言增加的,所以叫按键精灵全局变量。讲这四种变量前先要讲作用域,作用域是一个变量的有效范围,超出这个范围,就算有相同的变量名都不是同一个变量。



脚本全局变量:

不在函数或者过程中定义的变量是脚本全局变量。无论是否使用了Dim进行声明,作用域都是当前线程内的整个脚本。



局部变量:

在函数或者过程中使用Dim进行声明的变量是局部变量。如果没使用Dim进行声明默认是脚本全局变量,作用域是使用Dim进行声明的函数或者过程内(仅调用它的线程)。



环境变量:

在脚本中使用DimEnv声明的变量是环境变量。不能在函数或者过程中进行声明,作用域是按键精灵进程,可用于脚本线程之间传递数据。



按键精灵全局变量:

在脚本中使用Global声明的变量是环境变量。不能在函数或者过程中进行声明,作用域是按键精灵主线程及其子线程,可用于脚本主线程和子线程之间或者同一个主线程继承下来的子线程之间的传递数据。不同主线程及其子线程不在同一个作用域中。


注:如果同一个脚本中脚本全局变量和局部变量中使用了相同变量名,这时在声明了该变量的函数或者过程中作用域重叠,局部变量的作用域会覆盖脚本全局变量的作用域。


从上面的变量介绍可以看出,能在线程之间传递数据的只有环境变量和按键精灵全局变量。例如主线程序多个子线程传递数据可以这样写:



[按键精灵] 纯文本查看 复制代码
Global GlobalData1, GlobalData2, GlobalData3
GlobalData1 = "Data1"
Call BeginThread(Thread1)
GlobalData2 = "Data2"
Call BeginThread(Thread2)
GlobalData3 = "Data3"
Call BeginThread(Thread3)
Sub Thread1()
    MsgBox GlobalData1, 4096, "Thread1"
End Sub
Sub Thread2()
    MsgBox GlobalData2, 4096, "Thread2"
End Sub
Sub Thread3()
    MsgBox GlobalData3, 4096, "Thread3"
End Sub


这个方法有局限性,如果要重复调用同一个线程过程,并给它们传递不同数据就会产生冲突,比如下面这样写:



[按键精灵] 纯文本查看 复制代码
Global GlobalData1
GlobalData1 = "Data1"
Call BeginThread(Thread1)
GlobalData1 = "Data2"
Call BeginThread(Thread1)
GlobalData1 = "Data3"
Call BeginThread(Thread1)
Sub Thread1()
    MsgBox GlobalData1, 4096, "Thread1"
End Sub


运行后你会发现弹出的几个对话框的内容部分或者全部是相同的,和我们想要的结果不同,这是因为线程过程中,MsgBox还没及时取到数据,就被下一个对GlobalData1赋值修改了,最终导致不同子线程中MsgBox取到的值是相同的。如何解决这个问题呢?正规方法应该是用线程同步,比如互斥体,不过按键精灵没有自带这样的命令,而且就算有也使用比较麻烦,而且不小心会把脚本锁死。其它的脚本线程间传递数据的方法都有不可靠或者使用复杂等问题。针对此问题361度窗口插件中提供了线程间收发数据的命令,能够简单地实现父子线程之间的数据传递。相关命令有:



PostThreadData 发送线程数据
RecvThreadData 接收线程数据

例子如下:
[按键精灵] 纯文本查看 复制代码
'循环创建线程和给线程发送数据
i=0
For 3
    '创建线程
    tid = BeginThread(Thread1)
    '根据线程ID给线程发送数据
    Call Plugin.WndEx7_20.PostThreadData(tid, "线程数据" & CStr(i), 0)
    i = i + 1
Next
Sub Thread1()
    Do
        '接受当前线程数据
        If Plugin.WndEx7_20.RecvThreadData(data)=0 Then
            Exit Do
        End If
        Delay 50
    Loop
    MsgBox data, 4096, "Thread1"
End Sub



在按键精灵中和多线程有关的命令有:
EndScript 脚本停止运行
ExitScript 脚本退出运行
BeginThread 同时运行过程
StopThread 停止线程运行
PauseThread 暂停线程运行
ContinueThread 继续线程运行
GetThreadID 得到当前线程ID


这里主要讲的是EndScript和ExitScript命令,其它的看名称就知道作用了。EndScript和ExitScript都是停止运行,但功能上有差异。

EndScript:停止当前脚本线程。无论当前脚本线程是脚本主线程还是脚本子线程,使用它后都是停止当前的脚本线程,不影响其它脚本线程。


ExitScript:停止当前脚本主线程和相关的子线程。无论调用它的是脚本主线程还是脚本子线程,使用他后停止当前脚本主线程和相关的子线程,不影响其它脚本主线程和相关的子线程。如果使用可重复运行多开脚本,ExitScript不会停止使用该脚本多开的所有脚本线程,只会停止和和它有关的那个主线程和相关的子线程。




在按键精灵中和多线程有关的事件有:
OnScriptExit 脚本停止事件子程序
OnThreadExit 线程停止事件子程序

OnScriptExit:脚本主线程退出时自动调用此过程。这个过程的线程是要退出的脚本主线程,所以脚本主线程的脚本全局变量的作用域范围包括了这个过程。也就是说,脚本主线程的脚本全局变量它可以使用。


OnThreadExit:脚本子线程退出时自动调用此过程。这个过程的线程是要退出的脚本子线程,所以脚本子线程的脚本全局变量的作用域范围包括了这个过程。也就是说,脚本子线程的脚本全局变量它可以使用。



脚本中使用的361度窗口插件下载:
http://pan.baidu.com/s/1ntQswaP

本文转载于361度插件作者博客
http://bg361.blog.163.com/
楼主热帖
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|紫猫编程学园

GMT+8, 2024-3-29 00:40

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表