lua变量缺少local造成unity死锁

lua变量缺少local造成unity死锁

(金庆的专栏 2020.9.1)

这几天在开发 grpc-tolua, 可以在 unity 项目中使用 lua 发送 grpc 请求,无需生成代码.
现已实现 route_guide 示例中的全部4种rpc.
见:https://github.com/jinq0123/grpc-tolua

昨天的开发中就发现,运行 RecordRoute 和 RouteChat 之后Unity无法再次运行,必须杀进程。
在 await 语句添加 ConfigureAwait(false) 之后,好像 RouteChat 修复了,但 RecoreRoute 依旧。

ConfigureAwait(false) 保证了 await 之后不会抢占主线程,是解决死锁的一种方法。
grpc 源码中的 await 同样都跟着这句。

今天再次测试,发现 RouteChat 并未真正修复,仍有较大可能卡死。

最初的猜想是 Lua 协程,C# 异步造成线程死锁,因为对异步不熟,总是怀疑使用有误。
后来转变为查找让 Unity 卡死的阻塞式操作,但是因为日志显示不全,找遍代码都没结果。
除了在自己的代码中查找错误,还在 tolua 代码,grpc 代码中查找,到处怀疑。
今天一整天都在添加日志,重启Unity中度过。提出各种猜想,又反复验证。

依次采用了以下方法:

  • 比较C# route_guide 代码,查找区别
  • 为什么是 client streaming 类型的 rpc 有错
  • 查看 tolua 协程,Timer
  • 添加 Delay, 更改协程的运行次序,提高或降低复现几率
  • 函数入口和返回添加日志,证明其没有阻塞

查找错误的方法是在代码中添加日志,找到异常之处。
最终的现象是Unity没有Update()调用了,全部卡死。

错误源代码是这样的,错误版本中 awaiter 前面没有 local.

local function await(awaitable)
    local awaiter = awaitable:GetAwaiter()
    coroutine.wait_until(function()
        return awaiter.IsCompleted
    end)
end

因为想实现一个特殊版本的 await() 用于测试, 把 awaiter.IsCompleted 改为总是 false。
复制代码时,发现了变量缺少 local.
如果这个成为全局变量,第2次函数调用就会更改第1次调用的变量,我立刻意识到了这就是死锁的原因。
添加 local 之后测试,一切都正常了。

分析结果是因为 awaiter 更改后,await() 在任务完成前就返回了,
以致于后面的读取成为阻塞式操作,阻塞了主线程。

查错效率低的主要问题是 Unity 日志在卡死前的日志没有显示,这一点直到最后死锁复盘时才发觉。
因为日志缺失,根据日志得出的所有判断几乎都错了。
本来可以根据日志快速定位的原因,现在完全找错方向。

如果有工具警告全局变量,就可以避免这个错误。

Unity Profiler, VS Debugger 因为 Unity 完全卡死,所以没什么帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值