美文网首页
多线程中的lua同步问题

多线程中的lua同步问题

作者: 玛玛哈哈m | 来源:发表于2018-05-08 16:23 被阅读0次

    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函数的末尾添加两行:

    static void close_state (lua_State L) {
    global_State g = G(L);
    luaF_close(L, L->stack); /
    close all upvalues for this thread /
    luaC_freeallobjects(L); /
    collect all objects /
    luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
    luaZ_freebuffer(L, &g->buff);
    freestack(L);
    lua_assert(gettotalbytes(g) == sizeof(LG));
    pthread_mutex_unlock(&g->lock);
    pthread_mutex_destroy(&g->lock);
    (
    g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /
    free main block */
    }

    修改完成后,重新编译程序,问题解决。

    相关文章

      网友评论

          本文标题:多线程中的lua同步问题

          本文链接:https://www.haomeiwen.com/subject/ferwrftx.html