用互斥体解决多线程资源冲突问题

社区服务
高级搜索
猴岛论坛辅助工具用互斥体解决多线程资源冲突问题
发帖 回复
正序阅读 最近浏览的帖子最近浏览的版块
0个回复

用互斥体解决多线程资源冲突问题

楼层直达
mimi_rice

ZxID:55494225

等级: 上士
举报 只看楼主 使用道具 楼主   发表于: 2015-03-05 0

解决多线程资源冲突问题
本文按键学院提供技术支持


按键学院交流群(1群已满):376122403
零基础学按键精灵群(2群):372671254




引用

故事就从一位童鞋的悲惨经历说起吧。
那是一个雷雨交加的夜晚
这位童鞋熬夜写了一个关于《赤月传说》交易功能的多线程多开脚本。
狂喜之余立马投身测试
测试的结果却让他的脸变成了屎色
他开了15个窗口,挂了半小时,就有10个窗口崩溃了。

他首先想到的是,会不会是电脑不给力,线程开多了导致的崩溃?
于是,他只开了5个窗口

啊~5个窗口崩了3个
这个问题困扰了他一个月,
后来才发现!
原来,游戏里规定,交易只能是一对一的
他没有在脚本中做处理
于是,启动脚本之后,所有的号都争着和交易号进行交易,
只有一个窗口抢到了和交易号交易的机会,其它的窗口没有抢到,就不断循环判断导致窗口崩溃
就像10个人争抢一个茅坑一样,1个人抢到了,其余9个人都掉坑里了……


怎么才能让他们好好排队上厕所呢?
很多童鞋可能会立马想到互斥体。
将交易的那段代码用互斥体保护起来,当一个线程在执行交易代码时,其它的线程就无法进行交易操作。
为了方便大家学习和使用,我们的06老湿提供了一段Api创建互斥体的代码范例~







API函数


引用
{:4_95:}
要用到三个Api函数:
CreateMutex
WaitForSingleObject
ReleaseMutex






函数名称  CreateMutex
函数功能创建互斥体
参数参数1:指定一个SECURITY_ATTRIBUTES结构,或传递零值,表示使用不允许继承的默认描述符
参数2:如创建进程希望立即拥有互斥体,则设为TRUE。一个
互斥体同时只能由一个线程拥有。
参数3:指定
互斥体对象的名字。
返回值如执行成功,就返回互斥体对象的句柄;零表示出错。







函数名称  WaitForSingleObject
函数功能[size=13px]检测对象的信号状态,当函数的执行时间超过参数2设置的间隔时间,就返回无信号状态,
参数参数1:对象句柄
参数2:定时时间间隔
返回值WAIT_OBJECT_0 0x00000000 :核心对象已被激活
WAIT_TIMEOUT 0x00000102:等待超时
WAIT_FAILED 0xFFFFFFFF :出现错误,可通过GetLastError得到错误代码








函数名称  ReleaseMutex
函数功能释放由线程拥有的一个互斥体的控制权
参数参数:指定一个互斥体的句柄。
返回值非零表示成功,零表示失败。



步骤





1调用Api函数:CreateMutex函数创建一个新的互斥体,并且将创建之后返回的互斥体句柄赋值给环境变量:交易



2交易代码执行之前,调用Api函数:WaitForSingleObject函数, 设置互斥体使用时长为30秒。(如果一个交易操作需要3分钟,则这里的使用时长设置为大于等于3分钟。)


   当第一条线程执行到 WaitForSingleObject函数时,会获取30秒的互斥体使用时长,在这30秒时间内,只有第一条          线程可以执行被互斥体保护起来的代码段,其它的线程都在等待。



3交易代码执行之后,调用Api函数:ReleaseMutex函数, 释放互斥体使用权
   当30秒时间过后,第一条线程会释放对互斥体的控制权,让给下一条线程使用。






代码
  1. Declare Function CreateMutex Lib "kernel32" Alias "CreateMutexA" (lpMutexAttributes As Long , ByVal bInitialOwner As Long, ByVal lpName As String) As Long
  2. Declare Function ReleaseMutex Lib "kernel32" Alias "ReleaseMutex" (ByVal hMutex As Long)
  3. Declare Function WaitForSingleObject Lib "kernel32" Alias "WaitForSingleObject" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
  4. 'Declare Function CloseHandle lib "kernel32" (hdr as long) as Long
  5. Dimenv 交易
  6. 交易 = 创建互斥体()
  7. For 10
  8.     BeginThread  游戏交易
  9. Next
  10. Sub 游戏交易()
  11.     //绑定窗口
  12.     //登录帐号
  13.     //寻找npc
  14.     Call 锁定(交易, 30000)
  15.     //交易
  16.     Call 解锁(交易)
  17. End Sub
  18. Function 创建互斥体()
  19.     '/*随机生成互斥体名称
  20.     Dim TempStr, i
  21.     TempStr = "anjian_mutex_"
  22.     For i = 0 To 12
  23.         Randomize
  24.         TempStr = TempStr & Chr((24 * Rnd) + 65)
  25.     Next
  26.     '*/    
  27.     创建互斥体 = CreateMutex(0, true, TempStr)
  28. End Function
  29. Sub 关闭互斥体(hdr)
  30.     Call CloseHandle(hdr)
  31. End Sub
  32. Function 锁定(Hdr, Max)
  33.     锁定 = WaitForSingleObject(Hdr, Max)
  34. End Function
  35. Function 解锁(Hdr)
  36.     Call ReleaseMutex(Hdr)
  37. End Function
  38. /*
  39. Sub OnScriptExit()
  40.    TracePrint "关闭互斥体"
  41.    Call 关闭互斥体(交易)
  42. End Sub
  43. '*/  
注意1:
本例子中,在创建互斥体时,使用了随机产生互斥体的名称
随机名称是以 anjian_mutex_”开头并且加上12个随机字母
随机名称这样复杂是为了避免名称冲突,如果有一样的名称存在,那么当前的互斥体就会创建失败



注意2:

代码中还有一个CloseHandle函数,被注释掉了
因为,我们的主线程结束得比其它的十条线程快,所以当十条线程还在创建启动的过程中,主线程就已经结束,并且触发了脚本停止事件,执行了关闭互斥体的命令
这样会导致,刚创建的互斥体被关闭的情况
所以,如果主线程结束得比其他线程快,就不要使用关闭互斥体命令了
互斥体所占用的内存空间并不大,不关闭也不影响






引用
那么,如果游戏规定, 登录帐号和交易 这两个操作都只能一个一个进行操作呢?
那么我们就需要设置两个互斥体:
登录互斥体 和 交易互斥体  

代码:
  1. Declare Function CreateMutex Lib "kernel32" Alias "CreateMutexA" (lpMutexAttributes As Long , ByVal bInitialOwner As Long, ByVal lpName As String) As Long
  2. Declare Function ReleaseMutex Lib "kernel32" Alias "ReleaseMutex" (ByVal hMutex As Long)
  3. Declare Function WaitForSingleObject Lib "kernel32" Alias "WaitForSingleObject" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
  4. 'Declare Function CloseHandle lib "kernel32" (hdr as long) as Long
  5. Dimenv 交易,登录
  6. 登录 = 创建互斥体()
  7. 交易 = 创建互斥体()
  8. For 10
  9.     BeginThread  游戏交易
  10. Next
  11. Sub 游戏交易()
  12.     //绑定窗口
  13.       
  14.     Call 锁定(登录, 30000)
  15.     //登录帐号
  16.     Call 解锁(登录)
  17.     
  18.     //寻找npc
  19.     
  20.     Call 锁定(交易, 30000)
  21.     //交易
  22.     Call 解锁(交易)
  23. End Sub
  24. Function 创建互斥体()
  25.     '/*随机生成互斥体名称
  26.     Dim TempStr, i
  27.     TempStr = "anjian_mutex_"
  28.     For i = 0 To 12
  29.         Randomize
  30.         TempStr = TempStr & Chr((24 * Rnd) + 65)
  31.     Next
  32.     '*/    
  33.     创建互斥体 = CreateMutex(0, true, TempStr)
  34. End Function
  35. Sub 关闭互斥体(hdr)
  36.     Call CloseHandle(hdr)
  37. End Sub
  38. Function 锁定(Hdr, Max)
  39.     锁定 = WaitForSingleObject(Hdr, Max)
  40. End Function
  41. Function 解锁(Hdr)
  42.     Call ReleaseMutex(Hdr)
  43. End Function
  44. /*
  45. Sub OnScriptExit()
  46.    TracePrint "关闭互斥体"
  47. <span style="font-size: 14.2857151031494px;">Call 关闭互斥体(登录)</span>
  48.    Call 关闭互斥体(交易)
  49. End Sub
  50. '*/







{:5_141:}本文按键学院提供技术支持{:5_141:}
零基础学按键精灵2015年开始招生!

全面系统回合制脚本教学



« 返回列表
发帖 回复