2016-04-03 2 views
2

У меня есть сетевое приложение, которое использует сценарии Lua. После запуска приложения я создаю глобальное состояние Lua и загружаю все файлы сценариев, которые содержат различные функции, и для каждого клиента, который подключается, я создаю поток Lua для этого соединения.Отменить доход от хоста

// On start 
var GL = luaL_newstate(); 
// register functions... 
// load scripts... 

// On connection 
connection.State = lua_newthread(GL); 

Когда приходит запрос, в котором используется скрипт, я получаю глобальную функцию и вызываю ее.

var NL = connection.State; 

var result = lua_resume(NL, 0); 
if (result != 0 && result != LUA_YIELD) 
{ 
    // error... 
    result = 0; 
} 

if (result == 0) 
{ 
    // function returned... 
} 

Теперь, некоторые сценарии требуют ответа на что-то от клиента, так что выход в этих функциях, ждать его. Когда ответ приходит, сценарий возобновляется с lua_resume(NL, 1).

// Lua 
text("How are you?") 
local response = select("Good", "Bad") 

// Host 
private int select(IntPtr L) 
{ 
    // send response request... 
    return lua_yield(L, 1); 
} 

// On response 
lua_pushstring(NL, response); 
var result = lua_resume(NL, 1); 
// ... 

Моя проблема заключается в том, что мне нужно, чтобы иметь возможность отменить этот выход, и возврата из функции Lua, без выполнения каких-либо больше кода в функции Lua, и без добавления дополнительного кода скриптов. Другими словами, я в основном хочу, чтобы поток Lua выдавал исключение, возвращался к началу и забывал, что он когда-либо выполнял эту функцию.

Возможно ли это?

Одна вещь, которую я думал, может работать, но не сделал, звонил lua_error. Результатом стал SEHException по вызову lua_error. Я предполагаю, что сценарий в настоящее время не работает, но уступает.

ответ

0

В то время как я не нашел способ протирать нить сланца чистым (я не думаю, что это возможно), я нашел решение для выяснения того, как работает lua_newthread.

Когда поток создан, ссылка на него помещается в стек состояния «глобального» состояния, и он не собирается, пока он не будет удален оттуда. Все, что вам нужно сделать, чтобы очистить поток, удаляет его из стека с помощью lua_remove. Это требует регулярного создания новых потоков, но для меня это не проблема.

Теперь я отслеживаю созданные потоки и их индекс в стеке, поэтому я могу удалить их, когда поступил с ними по какой-либо причине (отмена, ошибка и т. Д.). Все остальные индексы обновляются, так как удаление будет сдвигать те, которые пришли после него.

if (sessionOver) 
{ 
    lua_remove(GL, thread.StackIndex); 

    foreach (var t in threads) 
    { 
     if (t.StackIndex > thread.StackIndex) 
      t.StackIndex--; 
    } 
} 
Смежные вопросы