seagate 发表于 2010-1-21 14:14:55

Cmud的全局变量、多线程和Event

从上周末到现在转入Cmud差不多快一周时间了,从Zmud的单线程架构
转换到Cmud的多线程架构,不能说自己现在对Cmud有多了解,但是经过
mister,killunix等人的帮助下也算稍微有点了解了。现在谈谈Cmud特色
的一些地方。Cmud比起Zmud有特色的地方很多,太多地方没弄明白。不过
这几天被Cmud的多线程架构折磨,算是有一点点个人理解。仅在这里抛砖
引玉,如果下面描述有误请多加提点。


    说起Cmud的多线程架构首先要注意的就是他的全局变量,由于是多线
程架构,所以全局变量很容易被两个以上线程共享,这时候你使用全局变
量就要非常注意。有一个很好的办法就是#section语法,这个语法就是对
变量提供保护区,在这个保护区内用到的全局变量会加锁,其他线程要用
到这个变量就要等#section {commands}解锁以后才能用。关键点在于你
修改全局变量或者防止其他线程修改你的全局变量的时候就需要对这个区
域加锁。但是这里衍生出另外一个热门话题就是死锁问题。举例来说:
    #trigger {A} {#section {#va var1 1;#if @var2>1 {commands}}
    #trigger {B} {#section {#va var2 1;#if @var1>1 {commands}}
当这两个触发同时运行的时候就会产生问题,由于触发A对var1变量加锁,
但是要等待触发B对var2解锁才能执行下一步,而触发B对var2变量加锁,
但是要等待触发A对var1解锁才能执行下一步,两个语句互相等待资源,
就导致程序陷入死循环,当然也就完蛋了!你如果用#thread查看的时候
就会发现问题。所以总的来说为了保护全局变量的一致性需要用#section
保护你的关键代码,但是不能多加,还有就是为了避免使用全局变量,最
好多用local变量,这种变量没有多线程竞争问题,但是local变量只能在
一个限定环境内执行,不能跨线程或者跨区域使用,多线程之间信息交流
还是要靠全局变量。


    多线程从上面看来引出了一大堆麻烦事情,看上去没有多少好处,但
是多线程不是没有优势的,在这里Cmud提供了Event机制和信号量。(其他
多线程好处没研究透,昨天开始看Event发现还是不错的东西)在Zmud时代
你要在多个触发语句之间做协调需要用到很多全局变量进行赋值或者用一些
set action “触发条件”,#sa 触发条件来处理并发,这些协调总的来说会
有很多问题,常常出现协调不一致,或者显示输出混乱导致触发停止,问题
不一而足,反正非常麻烦。利用Cmud的多线程机制和Event就可以很好的解
决这些问题。举例来说你战斗的时候可以用一个
             #alarm {0.5} {#raise onPerform}
来不停的触发发特殊技能事件,具体事件onPerform可以处理怎么发技能,
然后在有一个#trigger {战斗返回信息} 来处理是应该停止或者启动onPerform
事件。关闭事件了#raise发起事件也就无效了,战斗也停止了。这种交互就
节约了大量处理触发引起的一些列问题,提高了系统稳定性。Event还有一个
用途就是你在处理过程中主动发起一个事件处理,然后主线程用#waitsign来
等待一个信号量,事件处理完毕发起一个信号量,这样子就可以在一个触发
语句里面实现并发处理,而且不影响同步。Event中另外一个有点就是系统提
供了大量自动事件,有时候你用系统行走结束用onWalkEnd事件,房间相关有
onRoomEnter,onRoomWalk等事件方便处理,就不需要用触发来判断了,简
化了你做遍历算法的时候编码复杂度。至于Event其他好处就需要大家一起
挖掘了。

[ 本帖最后由 seagate 于 2010-3-1 03:49 PM 编辑 ]

jason 发表于 2010-1-21 15:02:33

cmud引入多线程却不支持协程真是昏了

seagate 发表于 2010-1-21 15:12:40

可以用信号量来进行线程间同步。不过有时候关键是不知道啥时候变成多线程了。所以除非你自己创建两个显式线程,否则用信号量同步难度也非常大。他还有一个同步方式是#waitthread,但是不知道怎么知道线程ID,不知道是不是可以显示创建一个带id的线程。这个东西比较麻烦。反正他的线程间全局变量没有自动加锁确实很恶心,正常来说全局变量的同步应该是内核处理的,用户只需要考虑少量的线程间同步就可以,现在cmud的情况就是大多数全局资源的锁他都不管,都要用户来处理。所以造成非常多的锁冲突,而且用户自己加锁一不小心就会变成死锁,cmud本身也没有死锁的解锁机制。我自己就碰到好几次。

lzkd 发表于 2010-1-21 15:16:04

过来用mush吧。。。。。。。嘿

killunix 发表于 2010-1-21 15:56:02

所以说,用section一定要小心,他的帮助文件里写的很清楚,cmud的开发人员也谈过这个问题,新版本不知有没有解决。

在处理多个触发之间关系的时候,建议你用%trigg()这个函数,很方便

grla 发表于 2010-1-21 16:18:11

不错不错 味道好极了

ddid 发表于 2010-1-21 17:31:17

对ZMUD系列不感冒的人…… 飘过~

seagate 发表于 2010-1-21 20:49:29

我用了Event发现Event比触发速度快多了,不过Event里面再使用#wa或者其他之类会导致多线程的一定要慎重!会有问题。如果不会引起多线程的倒是问题不大。自己测试吧!我使用#waitsign在event里面就非常混乱,90%情况是对的,10%情况不知道处于啥状态。我看帮助发现似乎和全局变量有关!#wa系列命令如果碰到全局变量一定要慎重,因为都会引出多线程,产生不可预知错误!Cmud就这点不好。 event其实相当于是一个内部触发,如果你使用自发提示来触发一个命令的话改用event速度会提高非常多,至少节约0.5秒左右和服务器交换时间。战斗中有时候会影响你的生死的!建议killunix战斗触发最好改用event来处理。还有比如领悟,跳楼之类用Event处理估计效果也不错,至少会提高效率!具体需要测试!

[ 本帖最后由 seagate 于 2010-1-21 08:51 PM 编辑 ]

gocold 发表于 2010-1-27 10:38:30

#NEWVAR 这个和 #local#va 有什么去区别

killunix 发表于 2010-1-27 12:21:49

#newvar是不搜索是否存在某个变量,直接创建新的
#loc 是内部变量,只能在一个脚本里执行
#var 全局变量,创建时会寻找是否存在,如存在切没有被使用,就直接赋值
页: [1] 2
查看完整版本: Cmud的全局变量、多线程和Event