金猪脚本(原飞猪脚本)以按键精灵教学为主,涉及UiBot,Python,Lua等脚本编程语言,教学包括全自动办公脚本,游戏辅助脚本,引流脚本,网页脚本,安卓脚本,IOS脚本,注册脚本,点赞脚本,阅读脚本以及网赚脚本等各个领域。想制作脚本和学习按键精灵的朋友可以添加按键精灵学习交流群:554127455 学习路上不再孤单,金猪脚本伴你一同成长.
故事就从一位童鞋的悲惨经历说起吧。
那是一个雷雨交加的夜晚
这位童鞋熬夜写了一个关于《赤月传说》交易功能的多线程多开脚本。
狂喜之余立马投身测试
测试的结果却让他的脸变成了屎色
他开了15个窗口,挂了半小时,就有10个窗口崩溃了。
他首先想到的是,会不会是电脑不给力,线程开多了导致的崩溃?
于是,他只开了5个窗口
啊~5个窗口崩了3个
这个问题困扰了他一个月,
后来才发现!
原来,游戏里规定,交易只能是一对一的
他没有在脚本中做处理
于是,启动脚本之后,所有的号都争着和交易号进行交易,
只有一个窗口抢到了和交易号交易的机会,其它的窗口没有抢到,就不断循环判断导致窗口崩溃
就像10个人争抢一个茅坑一样,1个人抢到了,其余9个人都掉坑里了……
怎么才能让他们好好排队上厕所呢?
很多童鞋可能会立马想到互斥体。
将交易的那段代码用互斥体保护起来,当一个线程在执行交易代码时,其它的线程就无法进行交易操作。
为了方便大家学习和使用,我们的06老湿提供了一段Api创建互斥体的代码范例~
API函数
要用到三个Api函数:
CreateMutex
WaitForSingleObject
ReleaseMutex
函数名称CreateMutex函数功能创建互斥体参数参数1:指定一个SECURITY_ATTRIBUTES结构,或传递零值,表示使用不允许继承的默认描述符
参数2:如创建进程希望立即拥有互斥体,则设为TRUE。一个互斥体同时只能由一个线程拥有。
参数3:指定互斥体对象的名字。返回值如执行成功,就返回互斥体对象的句柄;零表示出错。
函数名称WaitForSingleObject函数功能检测对象的信号状态,当函数的执行时间超过参数2设置的间隔时间,就返回无信号状态,参数参数1:对象句柄
参数2:定时时间间隔
返回值WAIT_OBJECT_0 0x00000000 :核心对象已被激活
WAIT_TIMEOUT 0x00000102:等待超时
WAIT_FAILED 0xFFFFFFFF :出现错误,可通过GetLastError得到错误代码
函数名称ReleaseMutex函数功能释放由线程拥有的一个互斥体的控制权参数参数:指定一个互斥体的句柄。
返回值非零表示成功,零表示失败。
步骤
1、调用Api函数:CreateMutex函数创建一个新的互斥体,并且将创建之后返回的互斥体句柄赋值给环境变量:交易
2、交易代码执行之前,调用Api函数:WaitForSingleObject函数, 设置互斥体使用时长为30秒。(如果一个交易操作需要3分钟,则这里的使用时长设置为大于等于30分钟。)
当第一条线程执行到 WaitForSingleObject函数时,会获取30秒的互斥体使用时长,在这30秒时间内,只有第一条 线程可以执行被互斥体保护起来的代码段,其它的线程都在等待。
3、交易代码执行之后,调用Api函数:ReleaseMutex函数, 释放互斥体使用权
当30秒时间过后,第一条线程会释放对互斥体的控制权,让给下一条线程使用。
代码
- Declare Function CreateMutex Lib "kernel32" Alias "CreateMutexA" (lpMutexAttributes As Long , ByVal bInitialOwner As Long, ByVal lpName As String) As Long
- Declare Function ReleaseMutex Lib "kernel32" Alias "ReleaseMutex" (ByVal hMutex As Long)
- Declare Function WaitForSingleObject Lib "kernel32" Alias "WaitForSingleObject" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
- 'Declare Function CloseHandle lib "kernel32" (hdr as long) as Long
- Dimenv 交易
- 交易 = 创建互斥体()
- For 10
- BeginThread 游戏交易
- Next
- Sub 游戏交易()
- //绑定窗口
- //登录帐号
- //寻找npc
- Call 锁定(交易, 30000)
- //交易
- Call 解锁(交易)
- End Sub
- Function 创建互斥体()
- '/*随机生成互斥体名称
- Dim TempStr, i
- TempStr = "anjian_mutex_"
- For i = 0 To 12
- Randomize
- TempStr = TempStr & Chr((24 * Rnd) + 65)
- Next
- '*/
- 创建互斥体 = CreateMutex(0, true, TempStr)
- End Function
- Sub 关闭互斥体(hdr)
- Call CloseHandle(hdr)
- End Sub
- Function 锁定(Hdr, Max)
- 锁定 = WaitForSingleObject(Hdr, Max)
- End Function
- Function 解锁(Hdr)
- Call ReleaseMutex(Hdr)
- End Function
- /*
- Sub OnScriptExit()
- TracePrint "关闭互斥体"
- Call 关闭互斥体(交易)
- End Sub
- '*/
复制代码
注意1:
本例子中,在创建互斥体时,使用了随机产生互斥体的名称
随机名称是以 “[backcolor=rgb(247, 247, 247)]anjian_mutex_”开头并且加上12个随机字母
随机名称这样复杂是为了避免名称冲突,如果有一样的名称存在,那么当前的互斥体就会创建失败
注意2:
代码中还有一个CloseHandle函数,被注释掉了
因为,我们的主线程结束得比其它的十条线程快,所以当十条线程还在创建启动的过程中,主线程就已经结束,并且触发了脚本停止事件,执行了关闭互斥体的命令
这样会导致,刚创建的互斥体被关闭的情况
所以,如果主线程结束得比其他线程快,就不要使用关闭互斥体命令了
互斥体所占用的内存空间并不大,不关闭也不影响
那么,如果游戏规定, 登录帐号和交易 这两个操作都只能一个一个进行操作呢?
那么我们就需要设置两个互斥体:登录互斥体 和 交易互斥体
代码:
- Declare Function CreateMutex Lib "kernel32" Alias "CreateMutexA" (lpMutexAttributes As Long , ByVal bInitialOwner As Long, ByVal lpName As String) As Long
- Declare Function ReleaseMutex Lib "kernel32" Alias "ReleaseMutex" (ByVal hMutex As Long)
- Declare Function WaitForSingleObject Lib "kernel32" Alias "WaitForSingleObject" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
- 'Declare Function CloseHandle lib "kernel32" (hdr as long) as Long
- Dimenv 交易,登录
- 登录 = 创建互斥体()
- 交易 = 创建互斥体()
- For 10
- BeginThread 游戏交易
- Next
- Sub 游戏交易()
- //绑定窗口
- Call 锁定(登录, 30000)
- //登录帐号
- Call 解锁(登录)
- //寻找npc
- Call 锁定(交易, 30000)
- //交易
- Call 解锁(交易)
- End Sub
- Function 创建互斥体()
- '/*随机生成互斥体名称
- Dim TempStr, i
- TempStr = "anjian_mutex_"
- For i = 0 To 12
- Randomize
- TempStr = TempStr & Chr((24 * Rnd) + 65)
- Next
- '*/
- 创建互斥体 = CreateMutex(0, true, TempStr)
- End Function
- Sub 关闭互斥体(hdr)
- Call CloseHandle(hdr)
- End Sub
- Function 锁定(Hdr, Max)
- 锁定 = WaitForSingleObject(Hdr, Max)
- End Function
- Function 解锁(Hdr)
- Call ReleaseMutex(Hdr)
- End Function
- /*
- Sub OnScriptExit()
- TracePrint "关闭互斥体"
- Call 关闭互斥体(登录)
- Call 关闭互斥体(交易)
- End Sub
- '*/