按键精灵教程:解决多线程资源冲突
1、故事就从一位童鞋的悲惨经历说起吧。那是一个雷雨交加的夜晚这位童鞋熬夜写了一个关于《赤月传说》交易功能的多线程多开脚本。狂喜之余立马投身测试测试的结果却让他的脸变成了屎色他开了15个窗口,挂了半小时,就有10个窗口崩溃了。
2、他首先想到的是,会不会是电脑不给力,线程开多了导致的崩溃?于是,他只开了5个窗口啊~5个窗口崩了3个这个问题困扰了他一个月,后来才发现!原来,游戏里规定,交易只能是一对一的他没有在脚本中做处理于是,启动脚本之后,所有的号都争着和交易号进行交易,只有一个窗口抢到了和交易号交易的机会,其它的窗口没有抢到,就不断循环判断导致窗口崩溃就像10个人争抢一个茅坑一样,1个人抢到了,其余9个人都掉坑里了……
3、怎么才能让他们好好排队上厕所呢?很多童鞋可能会立马想到互斥体。将交易的那段代码用互斥体保护起来,当一个线程在执行交易代码时,其它的线程就无法进行交易操作。为了方便大家学习和使用,我们的06老湿提供了一段Api创建互斥体的代码范例~
4、API函数
要用到三个Api函数:CreateMutexWaitForSingleObjectReleaseMutex
5、步骤
调用Api函数:CreateMutex函数创建一个新的互斥体,并且将创建之后返回的互斥体句柄赋值给环境变量:交易2、交易代码执行之前,调用Api函数:WaitForSingleObject函数, 设置互斥体使用时长为30秒。(如果一个交易操作需要3分钟,则这里的使用时长设置为大于等于30分钟。) 当第一条线程执行到 WaitForSingleObject函数时,会获取30秒的互斥体使用时长,在这30秒时间内,只有第一条 线程可以执行被互斥体保护起来的代码段,其它的线程都在等待。
1、交易代码执行之后,调用Api函数:ReleaseMutex函数, 释放互斥体使用权 当30秒时间过后,第一条线程会释放对互斥体的控制权,让给下一条线程使用。
6、代码
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
'*/
7、注意1:本例子中,在创建互斥体时,使用了随机产生互斥体的名称随机名称是以 “anjian_mutex_”开头并且加上12个随机字母随机名称这样复杂是为了避免名称冲突,如果有一样的名称存在,那么当前的互斥体就会创建失败
8、注意2:代码中还有一个CloseHandle函数,被注释掉了因为,我们的主线程结束得比其它的十条线程快,所以当十条线程还在创建启动的过程中,主线程就已经结束,并且触发了脚本停止事件,执行了关闭互斥体的命令这样会导致,刚创建的互斥体被关闭的情况所以,如果主线程结束得比其他线程快,就不要使用关闭互斥体命令了互斥体所占用的内存空间并不大,不关闭也不影响
9、那么,如果游戏规定, 登录帐号和交易 这两个操作都只能一个一个进行操作呢?那么我们就需要设置两个互斥体:登录互斥体 和 交易互斥体
代码:
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 "关闭互斥体"
<span style="font-size: 14.2857151031494px;">Call 关闭互斥体(登录)</span>
Call 关闭互斥体(交易)
End Sub
'*/