今天在改一个程序,改成部分逻辑用lua写,这个程序是多线程的。将程序中部分逻辑改成lua之后,各种非法访问内存错误,各种奇奇怪怪的问题,不分时间,不分地点的出现崩溃。从调用堆栈来看,基本都是使用lua造成的。在多线程中使用lua_newthread得到的lus_State仍然有时候程序会崩溃。基本上可以确定为多线程中操作lua 的问题了。

前几天我转载的一篇文章,文章写了关于lua多线程的作法。作法有二

1.每一个线程函数用lua_newthread产生一个新的lua_state 以后对lua操作都用这个lua_state

2.修改lua源码使之成为支持多线程的(修改lua 源代码中lua_lock lua_unlock宏)

对于第2条,那篇文中的例子是用 pthread_mutex_t 来进行线程同步的pthread_mutex_t,我对pthread_mutex_t 不熟,网上一查才知道一般是在linux下C语言进行线程同步用的,在windows下面一般多线程都用CRITICAL_SECTION,和内核对象来进行线程同步的。于是产生了这篇文章。

修改代码如下:

1.global_State加一个成员变量  m_cs

Code Snippet
  1. typedef struct global_State {
  2.   stringtable strt;  /* hash table for strings */
  3.   lua_Alloc frealloc;  /* function to reallocate memory */
  4.   void *ud;         /* auxiliary data to `frealloc' */
  5.   lu_byte currentwhite;
  6.   lu_byte gcstate;  /* state of garbage collector */
  7.   int sweepstrgc;  /* position of sweep in `strt' */
  8.   GCObject *rootgc;  /* list of all collectable objects */
  9.   GCObject **sweepgc;  /* position of sweep in `rootgc' */
  10.   GCObject *gray;  /* list of gray objects */
  11.   GCObject *grayagain;  /* list of objects to be traversed atomically */
  12.   GCObject *weak;  /* list of weak tables (to be cleared) */
  13.   GCObject *tmudata;  /* last element of list of userdata to be GC */
  14.   Mbuffer buff;  /* temporary buffer for string concatentation */
  15.   lu_mem GCthreshold;
  16.   lu_mem totalbytes;  /* number of bytes currently allocated */
  17.   lu_mem estimate;  /* an estimate of number of bytes actually in use */
  18.   lu_mem gcdept;  /* how much GC is `behind schedule' */
  19.   int gcpause;  /* size of pause between successive GCs */
  20.   int gcstepmul;  /* GC `granularity' */
  21.   lua_CFunction panic;  /* to be called in unprotected errors */
  22.   TValue l_registry;
  23.   struct lua_State *mainthread;
  24.   UpVal uvhead;  /* head of double-linked list of all open upvalues */
  25.   struct Table *mt[NUM_TAGS];  /* metatables for basic types */
  26.   TString *tmname[TM_N];  /* array with tag-method names */
  27.   CRITICAL_SECTION m_cs; /*windows mutithread */
  28. } global_State;

 

2.在lua_newstate加入初始化Critical_section的代码 InitializeCriticalSection(&g->m_cs);

Code Snippet
  1. LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
  2.   int i;
  3.   lua_State *L;
  4.   global_State *g;
  5.   void *l = (*f)(ud, NULL, 0, state_size(LG));
  6.   if (l == NULL) return NULL;
  7.   L = tostate(l);
  8.   g = &((LG *)L)->g;
  9.   L->next = NULL;
  10.   L->tt = LUA_TTHREAD;
  11.   g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT);
  12.   L->marked = luaC_white(g);
  13.   set2bits(L->marked, FIXEDBIT, SFIXEDBIT);
  14.   preinit_state(L, g);
  15.   g->frealloc = f;
  16.   g->ud = ud;
  17.   g->mainthread = L;
  18.   g->uvhead.u.l.prev = &g->uvhead;
  19.   g->uvhead.u.l.next = &g->uvhead;
  20.   g->GCthreshold = 0;  /* mark it as unfinished state */
  21.   g->strt.size = 0;
  22.   g->strt.nuse = 0;
  23.   g->strt.hash = NULL;
  24.   setnilvalue(registry(L));
  25.   luaZ_initbuffer(L, &g->buff);
  26.   g->panic = NULL;
  27.   g->gcstate = GCSpause;
  28.   g->rootgc = obj2gco(L);
  29.   g->sweepstrgc = 0;
  30.   g->sweepgc = &g->rootgc;
  31.   g->gray = NULL;
  32.   g->grayagain = NULL;
  33.   g->weak = NULL;
  34.   g->tmudata = NULL;
  35.   g->totalbytes = sizeof(LG);
  36.   g->gcpause = LUAI_GCPAUSE;
  37.   g->gcstepmul = LUAI_GCMUL;
  38.   g->gcdept = 0;
  39.   InitializeCriticalSection(&g->m_cs);
  40.   for (i=0; i<NUM_TAGS; i++) g->mt[i] = NULL;
  41.   if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) {
  42.     /* memory allocation error: free partial state */
  43.     close_state(L);
  44.     L = NULL;
  45.   }
  46.   else
  47.     luai_userstateopen(L);
  48.   return L;
  49. }

3.在close_state 加入删除CriticalSection的代码 DeleteCriticalSection(&g->m_cs);

Code Snippet
  1. static void close_state (lua_State *L) {
  2.   global_State *g = G(L);
  3.   luaF_close(L, L->stack);  /* close all upvalues for this thread */
  4.   luaC_freeall(L);  /* collect all objects */
  5.   lua_assert(g->rootgc == obj2gco(L));
  6.   lua_assert(g->strt.nuse == 0);
  7.   luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *);
  8.   luaZ_freebuffer(L, &g->buff);
  9.   freestack(L, L);
  10.   lua_assert(g->totalbytes == sizeof(LG));
  11.   DeleteCriticalSection(&g->m_cs);
  12.   (*g->frealloc)(g->ud, fromstate(L), state_size(LG), 0);
  13. }

4.修改lua_lock和lua_unlock宏如下

Code Snippet
  1. #ifndef lua_lock
  2. #define lua_lock(L) EnterCriticalSection(&(G(L)->m_cs))
  3. #define lua_unlock(L) LeaveCriticalSection(&(G(L)->m_cs))
  4. #endif

5.为了使用CRITICAL_SECTION我们比较通用的方法是包含头文件 windows.h,但包含后发现,lua库中的LoadString函数正好与windows  api LoadString同名。所以把lua库内部所使用的LoadString通通改为LUA_LoadString即可

修改完之后,在控制台写了四个线程一个一个主lua_state,四个线程使用lua_newthread得到的lua_state,没有再出现错误了。

windows lua 多线程 线程同步的更多相关文章

  1. windows核心编程 - 线程同步机制

    线程同步机制 常用的线程同步机制有很多种,主要分为用户模式和内核对象两类:其中 用户模式包括:原子操作.关键代码段 内核对象包括:时间内核对象(Event).等待定时器内核对象(WaitableTim ...

  2. 多线程 - 线程同步锁(lock、Monitor)

    1. 前言 多线程编程的时候,我们不光希望两个线程间能够实现逻辑上的先后顺序运行,还希望两个不相关的线程在访问同一个资源的时候,同时只能有一个线程对资源进行操作,否则就会出现无法预知的结果. 比如,有 ...

  3. Java多线程——线程同步

    在之前,已经学习到了线程的创建和状态控制,但是每个线程之间几乎都没有什么太大的联系.可是有的时候,可能存在多个线程多同一个数据进行操作,这样,可能就会引用各种奇怪的问题.现在就来学习多线程对数据访问的 ...

  4. Java基础-多线程-③线程同步之synchronized

    使用线程同步解决多线程安全问题 上一篇 Java基础-多线程-②多线程的安全问题 中我们说到多线程可能引发的安全问题,原因在于多个线程共享了数据,且一个线程在操作(多为写操作)数据的过程中,另一个线程 ...

  5. Java多线程 - 线程同步

    多线程操作同一个对象时,容易引发线程安全问题.为了解决线程安全问题,Java多线程引入了同步监视器. 同步代码块 同步代码块语法格式如下: synchronized(obj){ //此处的代码即为同步 ...

  6. Java分享笔记:创建多线程 & 线程同步机制

    [1] 创建多线程的两种方式 1.1 通过继承Thread类创建多线程 1.定义Thread类的子类,重写run()方法,在run()方法体中编写子线程要执行的功能. 2.创建子线程的实例对象,相当于 ...

  7. python多线程--线程同步

    如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步. 使用Thread对象的Lock和Rlock可以实现简单的线程同步,这两个对象都有acquire ...

  8. JAVA多线程线程同步问题

    线程同步 在多线程的编程环境下,可能看着没有问题的代码在运行几千上万或者更多次后,出现了一些看着很奇怪的问题,出现这样的问题的原因就是可能会有两个或者更多个线程进入了同一块业务处理代码中导致了判断失效 ...

  9. Windows编程之线程同步

    本笔记整理自:<Windows核心编程(第五版)> 目录 什么是线程同步 用户方式中的线程同步 原子访问:Interlocked系列函数 CRITICAL_SECTION:关键段 内核对象 ...

随机推荐

  1. 使用Redis实现高并发分布式序列号生成服务

    序列号的构成 为建立良好的数据治理方案,作数据掌握.分析.统计.商业智能等用途,业务数据的编码制定通常都会遵循一定的规则,一般来讲,都会有自己的编码规则和自增序列构成.比如我们常见的身份证号.银行卡号 ...

  2. 【转】python argparse用法总结

    转自:https://www.jianshu.com/p/fef2d215b91d 1. argparse介绍 是python的一个命令行解析包,非常编写可读性非常好的程序 2. 基本用法 prog. ...

  3. POJ1386Play on Words(欧拉回路)

                                                             Play on Words Time Limit: 1000MS   Memory L ...

  4. 1.3(Spring学习笔记)Spring-AOP

    一.AOP简介 AOP面向切面编程,是将一种横向抽取机制,将多个类中需要使用的方法提取出来. 例如,这里有两个类,一个Cat,一个Dog,动物都需要吃饭睡觉,如果按照传统的思想. 给两类中都添加吃饭和 ...

  5. u-boot中添加mtdparts支持以及Linux的分区设置

    简介 作者:彭东林 邮箱:pengdonglin137@163.com u-boot版本:u-boot-2015.04 Linux版本:Linux-3.14 硬件平台:tq2440, 内存:64M   ...

  6. 使用强大的可视化工具redislive来监控我们的redis

    原文:http://www.cnblogs.com/huangxincheng/archive/2016/06/08/5571185.html 作为玩windows的码农,在centos上面装点东西, ...

  7. 【java】File的使用:将字符串写出到本地文件,大小0kb的原因

    实现方法: 暂时写一种方法,将字符串写出到本地文件,以后可以补充更多种方法: public static void main(String[] args) { /** * ============== ...

  8. php实现简单视图模板(视图引擎)

    视图 视图,你所看见的部分. <?php echo 'hello, world'; 从简单开始理解 这就是个视图文件中的代码,没错就这么简单.视图,实际上是在 MVC 这种架构上提出的.MVC ...

  9. ASP.NET MVC DropdownList的使用

    1:直接使用HTML代码写 <select name="year"> <option value="2011">2010</opt ...

  10. 排查java.lang.OutOfMemoryError: GC overhead limit exceeded

    帮助客户排查java.lang.OutOfMemoryError: GC overhead limit exceeded错误记录: 具体网址: https://support.oracle.com/e ...