2015-06-24 95 views
4

我有一個主程序(在C)需要分支到lua_thread(主要繼續運行)。這個lua_thread調用一個lua_script.lua。這個lua_script包含一個while循環。一個lua變量控制着這個while循環。目前這個循環永遠運行。更改lua變量從C

lua_script.lua

--this loop runs forever, as the exit value is not set yet 
    a=0 
    while(a<=0) 
    do 
     print("value of a:", a) 
    end 

我的目標是此LUA變量(a)由主程序,使得其退出該無限循環變化。一旦這個循環結束,它退出線程並返回到主程序。

的main.c

#include <lua.h> 
#include <lauxlib.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <pthread.h> 
void *lua_thread() 
{ 
    int status, result; 
    double sum; 
    lua_State *L; 

    L = luaL_newstate(); 
    luaL_openlibs(L); 

    status = luaL_loadfile(L, "lua_script.lua"); 
    if (status) 
    { 
     fprintf(stderr, "Couldn't load file: %s\n", lua_tostring(L, -1)); 
     exit(1); 
    } 

result = lua_pcall(L, 0, 0, 0); 
    if (result) { 
     fprintf(stderr, "Failed to run script: %s\n", lua_tostring(L, -1)); 
     exit(1); 
    } 

    lua_close(L); 
    return 0; 
} 

int main(void) 
{  
    pthread_t p1; 
    pthread_create(&p1,NULL,lua_thread,NULL); 
    pthread_join(p1,NULL);  
    return 0; 
} 

如果你運行上面的代碼

cc -o xcute main.c -I/usr/include/lua5.2 -llua -lm -ldl -pthread 

將進入一個無限循環。我想以某種方式控制lua變量,並將其從主程序中更改爲a = 1,以使其從無限循環中出來。做這樣一個測試的原因是它會確保在主程序退出之前,這個線程首先通過控制lua變量退出。 請建議如何改變這個lua變量,以便它退出while循環。

+0

AFAIK Lua不是線程安全的 - 也就是說,每個lua_State一次只能從一個線程使用。 – immibis

回答

4

從一個不同的線程與一個正在運行的lua狀態進行交互並不一定安全,因此根據您計劃從C端進行更改的位置來修改腳本的全局變量可能是也可能不是一個有用的想法。

如果你想這樣做,你只需要使用lua C api在相應的lua狀態中設置適當名稱的全局變量。

另一種想法是創建一個should_exit全局函數,該函數在每個循環的開始或結束處調用,並且返回true時,會使lua代碼爲breakreturn。然後這個函數可以以任何線程適當的方式檢查C端想要的任何東西。

+0

這應該是「創建'should_exit'全局函數」。他已經有了一個全球變量。 – Mud

+0

@Mud真的,我有一個for循環控制變量,而不是一個全局變量。 –

1

爲什麼在Lua中有這個循環?您可以循環使用c線程,而是在每次迭代時使用一些入口函數(例如onEvent())。

如果循環是在Lua腳本,例如在設置 - 環 - 清理方案的情況下,您可以在協程運行腳本,並使用coroutine.yield()作爲循環條件。線程應該lua_resume()true價值或退出取決於您的C方條件。 (或者如果在循環之後進行Lua端清理,則繼續false

無論如何,Lua不是線程安全的,不能從多個線程同時調用。

0

我花了兩天的時間來想出這個。希望它能幫助別人節約時間。

的main.c

#include <lua.h> 
#include <lauxlib.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <pthread.h> 
#include <assert.h> 
#include <fcntl.h> 
#include <semaphore.h> 

void *lua_thread(void *arg) 
{ 
    int status, result, i; 
    double sum; 
    lua_State *L=(lua_State *)arg; 

    int a=0; 
    status = luaL_dofile(L, "lua_script.lua"); 
    if (status) { 
     fprintf(stderr, "Couldn't load file: %s\n", lua_tostring(L, -1)); 
     exit(1); 
    } 

    printf("Lua thread exiting\n"); 
    return 0; 
} 

int main(void) 
{ 
    lua_State *L; 
    L = luaL_newstate(); 
    luaL_openlibs(L); 

    //Open semaphore which will signal Lua loop to exit 
    sem_t *lex=sem_open("luaexitsem", O_CREAT, 0600, 0); 

    //Make sure value of the semaphore is 0 before we start running 
    //so that sem_post sets it to 1 later 
     int retval; 
     for(retval=0;retval==0;) { 
      retval=sem_trywait(lex); 
      printf("Dec sem val: %d\n", retval); 
     } 

    //Start Lua thread 
    pthread_t p1; 
    pthread_create(&p1,NULL,lua_thread,L); 

    sleep(5); 

    //Signal Lua script to exit 
    sem_post(lex); 

    //Wait for Lua thread to exit 
    pthread_join(p1,NULL); 

    //Cleanup 
    printf("Main exiting\n"); 
    lua_close(L); 
    sem_close(lex); 
    return 0; 
} 

要編譯

GCC -o主main.c中-I/USR /包含/ lua5.1 -llua5.1 -lm -ldl -pthread

lua_script。LUA

require "lualinuxthread" 
    a=1 
    while(not linuxthread.signaltoexit()) 
    do 
     print("value of a:", a) 
     a=a+1 
    end 

lualinuxthread.c

#define LUA_LIB 
#include "lua.h" 
#include "lauxlib.h" 
#include <semaphore.h> 
#include <errno.h> 
#include <fcntl.h> 

static int signaltoexit(lua_State *L) { 

    sem_t *lex=sem_open("luaexitsem", O_CREAT, 0600, 0); 

    int exitvalue=0, retval; 

    if (lex!=SEM_FAILED) 
    retval=sem_trywait(lex); 

    if (retval==-1) exitvalue=0; else exitvalue=1; 

    printf("signaltoexit - exitvalue: %d, retval: %d, %x\n", exitvalue, retval, lex); 

    lua_pushboolean(L, exitvalue); 

    sem_close(lex); 
    return 1; 
} 

static const luaL_Reg libfuncs[] = { 
{"signaltoexit", signaltoexit}, 
{NULL, NULL} 
}; 

LUALIB_API int luaopen_lualinuxthread (lua_State *L) { 

    luaL_register(L, "linuxthread", libfuncs); 
    return 1; 
} 

編譯:

GCC -O -O2 -fpic -shared lualinuxthread.c -o lualinuxthread.so -lpthread -llua5.1

謝謝

+0

你不需要使用信號量 - 由互斥鎖保護的全局變量(在C中)也可以。 – siffiejoe

+0

@siffiejoe由於這是一次性可輪詢布爾條件,它甚至沒有被互斥鎖保護。聲明它不穩定就足夠了。 – user3125367

1

哦,你在答案中努力了(雖然這確實是一個很棒的練習) 。事情可能會簡單得多:

#include <pthread.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

#include <lua.h> 
#include <lauxlib.h> 
#include <lualib.h> 

static volatile int shouldRun = 1; // 1. 

static int 
fn_sleep(lua_State *L) 
{ 
    lua_Integer n = luaL_checkinteger(L, 1); 
    sleep(n < 0 ? 0 : n); 
    return 0; 
} 

static int 
fn_shouldRun(lua_State *L) 
{ 
    lua_pushboolean(L, shouldRun); 
    return 1; 
} 

static void * 
thread_main(void *dummy) 
{ 
    lua_State *L = luaL_newstate(); 
    luaL_openlibs(L); 

    lua_register(L, "sleep", fn_sleep); // 2. 
    lua_register(L, "shouldRun", fn_shouldRun); 

    if (luaL_dofile(L, "script.lua")) { 
     fprintf(stderr, "%s\n", lua_tostring(L, -1)); 
     lua_pop(L, 1); 
    } 

    lua_close(L); // 3. 
    return 0; 
} 

int 
main(int argc, char *argv[]) 
{ 
    pthread_t thread; 
    pthread_create(&thread, NULL, thread_main, NULL); 

    sleep(5); 
    shouldRun = 0; // 1. 

    pthread_join(thread, NULL); 
    return 0; 
} 

script.lua:

print("Hi!") 

while shouldRun() do 
    print("Running!") 
    sleep(1) 
end 

print("Bye!") 

輸出:

Hi! 
Running! 
Running! 
Running! 
Running! 
Running! 
Bye! 

幾點需要注意:

  1. 輪詢退出條件通常不需要任何保護。如果shouldRun()與變量update同時被調用並且錯過了,那麼沒有什麼可擔心的 - 它會在下一次返回false。無論如何,你甚至不能猜測腳本在哪裏執行,只需[重新]設置值並等待完成。
  2. 對於一對特定的功能,不需要編寫一個要求/預載兼容模塊。將它們導出到全局名稱空間。
  3. 對錯誤的優雅關閉不只是exit()lua_close()將垃圾收集腳本使用的所有用戶數據,他們的__gc元方法可能會執行一些有用的操作,例如將緩衝區刷新到磁盤等。您將失去所有硬退出的機會。
+0

非常好....謝謝 – bislinux