<轉>多線程中的lua同步問題


轉自 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM