今天在改一个程序,改成部分逻辑用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. 洛谷 P1583 魔法照片【二级结构体排序】

    题目描述 一共有n(n≤20000)个人(以1--n编号)向佳佳要照片,而佳佳只能把照片给其中的k个人.佳佳按照与他们的关系好坏的程度给每个人赋予了一个初始权值W[i].然后将初始权值从大到小进行排序 ...

  2. golang笔记:unsupported driver -> Scan pair: <nil> -> *string

    golang里,操作mysql数据库,使用查询语句的时候,一般的写法 rows, err := db.Query("select name from table") if err ...

  3. WebApi 的三种寄宿方式 (二) - 宿主和控制器不在一个程序集

    新建一个类库: SelfHost: 方法一: 1.添加对MyControllers类库的引用. 2.在控制台代码中加入一行代码: 当然,可以添加多个程序集.(记得引用) var config = ne ...

  4. [BZOJ 2817] 波浪

    Link: BZOJ 2817 传送门 Solution: 算是比较神的DP了吧, 首先这个绝对值处理起来很难受,肯定要想办法去掉 于是想到从小到大插入的方式,便不存在绝对值的问题了 插入一个数只有5 ...

  5. [BZOJ 2006] 超级钢琴

    Link: https://www.lydsy.com/JudgeOnline/problem.php?id=2006 Algorithm: 对于此类区间最值类问题,我们可以通过控制一端不变来寻找当前 ...

  6. SD 一轮集训 day1 carcar

    可以发现每条边只能选一次或者两次,并且最后每个点的度数(∑邻接边选的次数和)都是偶数(代表有欧拉回路). 然后根据题意列一个 n 行 m+1 列的01矩阵,每一行代表一个异或方程组(每个点的度数是偶数 ...

  7. [BZOJ2226]LCMSum

    转化一下,$\sum\limits_{i=1}^n[i,n]=n\sum\limits_{i=1}^n\dfrac i{(i,n)}$ 枚举$d=(i,n)$,上式变为$n\sum\limits_{d ...

  8. Java多线程——AQS框架源码阅读

    AQS,全称AbstractQueuedSynchronizer,是Concurrent包锁的核心,没有AQS就没有Java的Concurrent包.它到底是个什么,我们来看看源码的第一段注解是怎么说 ...

  9. oop 知识点回顾

    1.抽象,封装 2.继承:连接类的层次模型,并且允许类的重用,提供共性的方法,从现有的类派生(方法的重写,扩展) 派生:新类继承了基类,那么新类就是派生类,适合更合适的需要 3.多态:允许不同的类的对 ...

  10. Linux下的echo输出换行符

    echo -e "text1\ntext2" -e表示开启转移字符