在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
转自 http://www.cnblogs.com/ghost240/p/3526185.html 最近写paintsnow::start时出现了一个非常麻烦的BUG,程序的Release版本大约每运行十几次就会有一次启动时崩溃(Debug版本还没崩溃过),崩溃点也不固定。经过简单分析之后,确定是线程同步的问题。于是便修改了线程通信的代码,并使用pthread_mutex_lock/unlock来防止冲突。重新编译后,崩溃频率有所减少。但是每运行约四十次,还是免不了崩溃一次,而且冷启动时崩溃概率更大。 在VC中的Release版本中设置Generate Debug Info后,重复多次运行程序,好不容易得到了几次崩溃记录。综合这几次的崩溃点,可以发现崩溃基本都发生在重分配内存(operator new())时,而且调用堆栈中还显示调用过程中有luaVM的参与。经过多日跟踪,终于发现问题所在,特作记录。 首先简单说一下paintsnow的组织结构。paintsnow::start主要是由两个线程并行执行的,其中一个负责构架、绘图、消息处理等,由底层核心paintsnow.lib提供,另一个执行lua脚本,由luaVM和一些Paintsnow API构成。由于两个线程有时候需要调用另一个线程所提供的功能,因此可能会出现两个线程冲突的问题。之前的代码仅仅是对脚本线程call核心线程时做过调用转接和加锁处理,但是实际上有时核心线程也会call脚本(通常出现在各种回调函数中)。 网上的资料说解决多线程调用同一个luaVM的有效方案是使用lua_newthread来创建一个脚本线程单元,然后用新创建的单元作为lua_State来call。这一招在通常情况下是非常管用的,因为它成功避免了lua栈上的冲突。painsnow以前的方案就是这样写的。可是问题就出在lua本身为了兼容标准,并不包含线程同步的处理函数,所谓的newthread只是逻辑上的thread而非操作系统概念的thread,因此这样调用luaVM依然存在着重入的风险,特别是在内存重分配时会产生意思不到的错误。 当然,对于lua这种设计得非常优雅的库,自然对多线程有过考虑。通过lua的源码可以看出,lua在每一个不可重入的函数中都用lua_lock创建了一个锁以保证同步。默认情况下,由于同步锁并不包含在标准库中,所以lua_lock实际只是一个空宏:(llmits.h中有定义) #define lua_lock(L) ((void)0) 如果想要添加多线程支持,需要重写它和lua_unlock两个宏。这不是难事,以添加pthread提供锁功能为例: 在lstate.h中,对GlobalState结构新加一个成员: pthread_mutex_t lock; 然后在lua_newstate中添加初始化代码: pthread_mutex_init(&g->lock, NULL); 接着重定义lock/unlock宏(写在原定义前面即可): #define lua_lock(L) pthread_mutex_lock(&(G(L)->lock)); #define lua_unlock(L) pthread_mutex_unlock(&(G(L)->lock)); 最后在close_state函数的末尾添加两行:
vc++ lua线程同步代源码修改 见 http://www.cnblogs.com/zhangdongsheng/p/3679024.html |
请发表评论