转自 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 */
}

vc++ lua线程同步代源码修改 见 http://www.cnblogs.com/zhangdongsheng/p/3679024.html

<转>多线程中的lua同步问题的更多相关文章

  1. 多线程中的lua同步问题

    最近写paintsnow::start时出现了一个非常麻烦的BUG,程序的Release版本大约每运行十几次就会有一次启动时崩溃(Debug版本还没崩溃过),崩溃点也不固定.经过简单分析之后,确定是线 ...

  2. C# .net 多线程中集合数据同步

    from:http://www.cnblogs.com/GavinCome/archive/2008/04/09/1145250.html C# .net 多线程中集合数据同步(转) 集合类通常不是线 ...

  3. java多线程中并发集合和同步集合有哪些?区别是什么?

    java多线程中并发集合和同步集合有哪些? hashmap 是非同步的,故在多线程中是线程不安全的,不过也可以使用 同步类来进行包装: 包装类Collections.synchronizedMap() ...

  4. python 多线程中的同步锁 Lock Rlock Semaphore Event Conditio

    摘要:在使用多线程的应用下,如何保证线程安全,以及线程之间的同步,或者访问共享变量等问题是十分棘手的问题,也是使用多线程下面临的问题,如果处理不好,会带来较严重的后果,使用python多线程中提供Lo ...

  5. 进程?线程?多线程?同步?异步?守护线程?非守护线程(用户线程)?线程的几种状态?多线程中的方法join()?

    1.进程?线程?多线程? 进程就是正在运行的程序,他是线程的集合. 线程是正在独立运行的一条执行路径. 多线程是为了提高程序的执行效率.2.同步?异步? 同步: 单线程 异步: 多线程 3.守护线程? ...

  6. Java多线程中的竞争条件、锁以及同步的概念

    竞争条件 1.竞争条件: 在java多线程中,当两个或以上的线程对同一个数据进行操作的时候,可能会产生“竞争条件”的现象.这种现象产生的根本原因是因为多个线程在对同一个数据进行操作,此时对该数据的操作 ...

  7. Redis中的原子操作(2)-redis中使用Lua脚本保证命令原子性

    Redis 如何应对并发访问 使用 Lua 脚本 Redis 中如何使用 Lua 脚本 EVAL EVALSHA SCRIPT 命令 SCRIPT LOAD SCRIPT EXISTS SCRIPT ...

  8. .NET面试题解析(07)-多线程编程与线程同步

      系列文章目录地址: .NET面试题解析(00)-开篇来谈谈面试 & 系列文章索引 关于线程的知识点其实是很多的,比如多线程编程.线程上下文.异步编程.线程同步构造.GUI的跨线程访问等等, ...

  9. c#初学-多线程中lock用法的经典实例

    本文转载自:http://www.cnblogs.com/promise-7/articles/2354077.html 一.Lock定义     lock 关键字可以用来确保代码块完成运行,而不会被 ...

随机推荐

  1. Disruptor源码分析

    本文将介绍Disruptor的工作机制,并分析Disruptor的主要源码 基于的版本是3.3.7(发布于2017.09.28) 水平有限,如有谬误请留言指正 0. 什么是Disruptor? Dis ...

  2. HDU 2700 Parity(字符串,奇偶性)

    Parity Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  3. centos7常用系统维护命令

    一.开机自启动服务列表 #开机自启动 apache服务 systemctl enable httpd.service #开机自启动iptables服务 systemctl enable iptable ...

  4. 【枚举】【前缀和】【map】ICM Technex 2017 and Codeforces Round #400 (Div. 1 + Div. 2, combined) C. Molly's Chemicals

    处理出前缀和,枚举k的幂,然后从前往后枚举,把前面的前缀和都塞进map,可以方便的查询对于某个右端点,有多少个左端点满足该段区间的和为待查询的值. #include<cstdio> #in ...

  5. 计算数字出现的次数 Exercise07_03

    import java.util.Scanner; /** * @author 冰樱梦 * 时间:2018年下半年 * 题目:计算数字出现的次数 * */ public class Exercise0 ...

  6. 【MySQL笔记】数据操纵语言DML

    1.数据插入   INSERT INTO table_name (列1, 列2,...) VALUES(值1, 值2,....),(第二条),(第三条)...   注: 1)如果表中的每一列均有数据插 ...

  7. 如何判断一个请求是不是ajax请求

    原文:http://blog.csdn.net/easy_is_good/article/details/53609057 public boolean isAjaxRequest(HttpServl ...

  8. 【sql】mysql数据库做两条数据替换的操作,不使用第三方变量

    需求: 1.将数据库中两条数据中的唯一约束列  做值的替换 原始思想: 将两条数据查出来,在程序中设置第三方变量,进行两条数据的替换,然后将原始两条数据删除,将新的两条替换后的数据插入. 新思想: 1 ...

  9. 【SQL】查询数据库中某个字段有重复值出现的信息

    select name,mobile from [GeneShop].[dbo].[xx_member] where mobile in ( SELECT mobile FROM [GeneShop] ...

  10. 【Git】GitHub for Windows使用(3) GitHub Flow的使用

    第三章了,关于GitHub上有一个Pull Request,是展示本项目或资源所有的Pull 请求的. 而这个开发流程是基于GitHub Flow的开发模式. 网上关于GitHub Flow简单的介绍 ...