ToLua Timer mechanism

 

Speaking from a Bug:

Found in the internal demo players have a task to follow the logic Npc hung up.

telnet to connect the device to the problem, things began to engage in

This follows the logic is driven by a Timer. The Timer will start when the main character is created. Initially not considered a problem Timer itself. Suspect there are various places on the return flow situation

Dynamic get rid of a few functions are not implemented to Description Timer callback not called to. Suspect Timer itself

Timer output of the state, found to be running = true. I feel very surprised. Also read Timer in other fields found to have a handle. Output of view the next, found a removed = true.

Here wonder, explanation is abnormally removed the realization began to see the Timer:

 

Timer.lua create a Timer process is as follows:

1. Timer.New()

  Create a table yuan, the underlying field initialization. Running = false ...

2. Timer.Start ()

  1) Create a Handle from UpdateBeat

  By calling UpdateBeat: CreateListener, incoming Timer.Update and Timer function return value itself Handle, its role is a list of Node.

  代码: self.handle = UpdateBeat:CreateListener(self.Update, self)

  2) Sign in to UpdateBeat:

  That is, the handler as a node linked list into a list UpdateBeat's.

  代码: UpdateBeat:AddListener(self.handle)

    3). At this time, the Timer class initialization process is complete. Timer.Update follow-up waiting to be called up. You can see the main content is in fact UpdateBeat years.

  4) To understand the invocation Handle management and Timer.Update we must think UpdateBeat code

  5). UpdateBeat is defined in the event.lua

       

   We can see a _event metatable

  6) concerns the contents _event:

  #1 _event.CreateListener(func, obj)

  That is above 1 function) in the call, func here is Timer.Update, obj is the Timer itself.

  Here judged self.keepSafe, i.e. 5) defined in the second parameter of true UpdateBeat so here self.keepSafe = true.

  You can see the case keepSafe of, func and obj is wrapped into a xfunctor where this xfunctor read, is a xpcall package. That is keepSafe the event is executed with xpcall way when func actual call. Wrong, then returns throwing the wrong information. 

  Followed by several other fields, including cached package the value of the field xpcall function Timer.Update . Implement two pointers (_prev, _next) doubly linked list of needs, and we have to check bug concern removed = to true . Can see at the beginning of Timer.Start application Handle, this is the true state of removed.

               

            

  #2_event.AddListener

  After creating the Handle, the interface is registered by AddListener linked list can be seen here judge the effect of this field is self.lock lock self.list. That avoid when operating list, there are other logic to change this list.

  The lock field is set when performing an Update to true after the completion of the implementation of a change in the process lock false is true, if there are other AddListener behavior, will conduct the Add to cache a temporary list:.. Self. opList in, rather than self.list

  This list cache Add operation that is function () self.list:... After pushnode (handle) end and then wait to perform an Update, the Add the cache operations are performed again (RemoveListener empathy) 

            

  #3 _event.__call

  This function is performed when the calling operation _event. Below UpdateBeat () 

            

  __call function first locked lock = true. Then use the iterator generator ilist traverse the list list. This list is our AddListener Operating Storage doubly linked list of Timer. (ilist see detailed explanation below)

  . Each iteration of i shall be a handle, f is xpcall packaging Timer.Update function and then calls the function f, the result of a successful return xpcall identity:. Flag, error msg If an error occurs, the error is thrown with LuaException and calls. _list.remove, removing the Node from the list, and unlock: lock = false

  (There is a problem, if one of Timer wrong, then unlocked, really stuffed behind Timer Timer come in, are we going to bomb ?? seek to explain.)

  If all normal circumstances, would be to cache the Add / RemoveListener of operations performed again at the end.

            

  ilist list.lua iterator can see, the iterative returns generated depending on the nature of the for statement Lua three values: Iterated Function (list.next), a steady state (i.e. the _list), control variables (useless ). then a constant state variable and control parameters for the iterative function to call, and then the obtained return value assigned to the key for loop, value (<var-list>)

  So iterative function list.next. This function requires only a constant state (first time list, in fact, the head node, followed by each node) can, because directly accessible through next next. When the next is when the first node, loop end.

  for circular definition:

   for <var-list> in <exp-list> do

list.lua:

            

            

2. 看了那么多代码, 发现控制removed = true的地方有两处: CreateListener时和执行list:remove时.
 考虑到Create是一开始调用的, 不可能一开始就挂了, 所以应该是list.remove的时候, 再看调用list.remove的地方, 有两处, 一处是RemoveListener, 一处是 _event.__call中遍历执行Update时,出错了会执行remove.
 第一处, RemoveListener时, Timer.handle.running肯定是false的. 所以肯定是第二处了, 第二处是xpcall调用的, 出问题肯定有LuaException抛出. 但是查了抛错Dump网站发现没有该用户的报错日志.
 这就尴尬了..... 后面考虑到我们做了灰度测试开关, 只有部分用户的报错信息会上传, 于是找了另外几个出问题的账号, 终于发现有个用户在反馈出错的时间, 在抛错网站上, 有个几分钟前的LuaException, 就是这个Timer的执行流程里抛的......
 于是, 结论: 出错必有LuaException, 出错找不到log, 别忘了灰度测试比例, 尽量在内部测试时放开上报比例.
 
 
PS: 在出错时 执行了timer.remove. 解开了lock, 此时removed = true, running = true. 这种操作, 是否值得商榷?
 
 
 
 

Guess you like

Origin www.cnblogs.com/wmalloc/p/11245423.html
Recommended