В c++ я не силен поэтому ищу помощь.пытаюсь выполнить функцию из нового потока "lua_State* L1 = lua_newthread(L);" если раньше код "32 dit версии quik" работал почти безупречно
Код
lua_State* L1 = lua_newthread(L);
lua_gc(L1, LUA_GCSTEP, 100); // выполняет постепенный этап сбора мусора
lua_pushstring(L1, "main1");//Находит в стеке Lua функцию по ее названию и помещает ее наверх стека
lua_gettable(L1, LUA_GLOBALSINDEX);
lua_pcall(L1, 0, 0, 0);
то 64bit версии я уже так сделать не могу
Код
void newpotok(lua_State* L)
{
while (lua_isfunction(L, 1) != 1)
{
lua_getglobal(L, "main1"); Sleep(100); // ТУТ ЦИКЛ ТК НЕ ВСЕГДА НАХОДИТ НУЖНУЮ ФУНКЦИЮ ПРАВДА В ЭТОМ СОСТОЯНИИ ФУНКЦИЯ РАБОТАЕТ
}
lua_State* L1 = lua_newthread(L);
lua_settop(L1, 0);// уст кол-во элементов в стеке. 0 - очистить стек.
while (lua_isfunction(L1, 1) != 1)
{
lua_xmove(L, L1, 1);); ТУТ МЕНЯЛ ЗНАЧЕНИЯ МЕСТАМИ НИ ЧЕГО ПЕРЕДАЧА ФУНКЦИИ ДРУГОМУ ПОТОКУ
lua_getglobal(L1, "main1"); Sleep(100); //
}
lua_pcall(L1, 0, 0, 0); //////////// НЕ ПОЛУЧАЕТСЯ ВЫПОЛНИТЬ ////////////////////////////////////////////////////////////////////////
};
static int forLua_runMAIN1(lua_State* L)
{
std::thread thr(newpotok, L); //Запускает выполнение функции MyCallback() в отдельном потоке
thr.detach(); //Отсоединяет созданный поток от основного, делая его "фоновым"
return (0); //Завершает работу функции forLua_StartCallback, при этом функция MyCallback продолжает работать в отдельном потоке
}
Если задачей было сократить поголовье сишников, то задача решена успешно, половину свезли в дурку, вторую в кардиологию. Код у вас "не всегда находит нужную функцию", потому что никакой синхронизации нет, эти ваши while это мертвому припарка. В частности, пока вы в своем while ждете чудес, основной поток мог уже вообще завершиться, не находите? Квик ваши луа-конструкции при этом зачистит, а нативный поток так и останется тарахтеть в фоне до второго пришествия, точнее, пока не случится access violation и обвалит весь квик. По идее, надо lua_newthread вызвать в главном потоке, заполнить ему стек чем вам там нужно, и уже потом отдать созданный стек новому сишному потоку. И в основном потоке перед завершением (основного потока) дожидаться всех вторичных, а не просто detach() и живи как хочешь. Затем, вы делаете lua_xmove в цикле, который выполнится неизвестно сколько раз. Сколько значений вы выдернули в итоге из основного стека в новый? При этом основной поток продолжает работать параллельно и что-то там пихает в свой стек, а вы у него из-под носа это выдергиваете. И т.д. и т.п.
получилось? это в 32 бит версии могло такое прокатить
и это я отбросил все условия предположил что main у меня в бесконечном цикле к примеру а в main1 функции скрипта стоит одна строка message("не получается") и все равно вы ее не запустите с t1
кажется дошло до меня (1 Создает новый поток, толкает его в стек и возвращает указатель на lua_State, который представляет этот новый поток.) уже повод призадуматься буду углубляться в знания значит Спасибо)
Алексей написал: (1 Создает новый поток, толкает его в стек и возвращает указатель на lua_State, который представляет этот новый поток.
Таки нет, оно вообще никакой поток не создает. Оно создает стейт для нового потока, и вы когда с ним вызываете lua_pcall, вы выполняете вызываемую функцию в том же самом потоке, только в другом стейте. Вам надо этот стейт передать теперь новому нативному потоку (а не основной стейт, как у вас было). Основной стейт из нового потока вообще трогать нельзя.
#define STRICT
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define NOMINMAX
#define WINVER 0x0600
#define _WIN32_WINNT WINVER
#include <Windows.h>
#include <process.h>
extern "C"
{
#include "luaconf.h"
#include "lua.h"
#include "lauxlib.h"
}
#pragma comment(lib, "lua5.1.lib")
// здесь будет храниться ссылка на стейт нового потока.
// глобальная переменная - плохое решение, но для демки сойдет,
// более интересные варианты только добавят ненужной здесь сложности
static int tref = LUA_NOREF;
// это "полезная" функция, выполняемая в новом потоке
static void some_useful_function(lua_State * s)
{
// показываем сообщение о запуске
lua_getglobal(s, "message");
lua_pushliteral(s, "Эта функция выполняется в новом потоке. Выполняется, выполняется...");
lua_call(s, 1, 0);
// три секунды имитируем бурную деятельность
::Sleep(3000);
// показываем сообщение об остановке
lua_getglobal(s, "message");
lua_pushliteral(s, " ...кончила выполняться.");
lua_call(s, 1, 0);
}
// это стартовая функция для нашего нового потока
static unsigned int __stdcall thrd(void * pvoid)
{
// сохраняем переданный стейт.
// обратите внимание, что в этом потоке мы работаем только со стейтом,
// созданным специально для этого потока. мы никогда не трогаем стейты
// других потоков и другие потоки не должны трогать наш стейт
lua_State * n = static_cast<lua_State *>(pvoid);
// вызываем "полезную" функцию, передавая ей свой стейт
::some_useful_function(n);
// освобождаем ссылку на свой стейт, чтобы коллектор мог его прибить. если
// этого не сделать, стейт доживет до закрытия квика даже после остановки
// запустившего нас [в огород] скрипта (т.е. будет утечка памяти)
luaL_unref(n, LUA_REGISTRYINDEX, ::tref);
::tref = LUA_NOREF;
// с этого момента коллектор имеет право прибить наш стейт когда хочет, т.е.
// для нас его уже не существует, хотя, возможно, где-то в дебрях квика он
// еще будет болтаться некоторое время
n = nullptr;
// сейчас мы вернем управление и поток будет прибит. это приведет к тому, что
// хэндл потока, на котором ждет наш main, перейдет в состояние signaled,
// функция WaitForSingleObject вернет управление и main будет разблокирован
return 0;
}
// это main для квика (внезапно сишный)
static int qmain(lua_State * s)
{
// создаем новый стейт для потока.
// стейт также появится на вершине стека s
lua_State * n = lua_newthread(s);
// создаем ссылку на стейт, чтобы коллектор случайно не прибил его раньше времени.
// функция также выдернет стейт n с вершины стека s, вернув стек s в состояние,
// в котором он был до вызова lua_newthread
::tref = luaL_ref(s, LUA_REGISTRYINDEX);
// создаем нативный поток и передаем ему созданный стейт n
unsigned int tid;
HANDLE h = reinterpret_cast<HANDLE>(::_beginthreadex(NULL, 0, ::thrd, n, CREATE_SUSPENDED, &tid));
if(NULL == h)
{
// в случае ошибки поток не создан, поэтому не забываем прибить ссылку на новый стейт,
// иначе он останется в памяти до завершения квика (утечка памяти)
luaL_unref(s, LUA_REGISTRYINDEX, ::tref);
::tref = LUA_NOREF;
luaL_error(s, "_beginthreadex failed");
}
// обратите внимание, что в текущем потоке трогать стейт n больше нельзя, у него теперь новый хозяин,
// который позаботится также и о его освобождении. поэтому мы сразу же обнуляем указатель на стейт,
// чтобы случайные попытки туда влезть вызывали крэш
n = nullptr;
// запускаем новый поток на выполнение
::ResumeThread(h);
// здесь main может делать что-то другое, второй поток работает параллельно. но
// перед тем, как из мейна выйти, нужно убедиться, что все дополнительные потоки уже завершены.
// по-хорошему им сначала надо как-то посигналить "все бросай и на выход бегом", а уже потом ждать, но
// мы не будем лезть в дебри в рамках простой демки. поскольку нам в main особо делать нечего, мы сразу
// переходим к ожиданию завершения второго потока. попробуйте закомментировать следующую строку, если
// хотите посмотреть, как через три секунды к квику придет внезапный полярный зверек
::WaitForSingleObject(h, INFINITE);
// не забываем закрыть хэндл потока, иначе он доживет до закрытия квика (утечка хэндла)
::CloseHandle(h);
return 0;
}
extern "C" __declspec(dllexport) int qtest(lua_State * s)
{
// мы хотим, чтобы в качестве колбека main работала наша сишная qmain
lua_pushcclosure(s, qmain, 0);
lua_setglobal(s, "main");
return 0;
}
По созданию нативного потока я не стал связываться с сложным "_beginthreadex" а поступил проще
Код
void pr(lua_State * A)
{thread athr1(newpotok, A); athr1.detach();}
static int forLua_runMAIN1(lua_State * A)
{thread athr(pr, A);athr.join(); return(0);}
поясню почему; сначала вызывается поток join() для того чтобы упорядочить порядок вызовов если мы запускаем несколько потоков в каждом из которых выполняется конкретная функция join() выступает как электронное табло в сбербанке к примеру а если мы выполним сразу detach() то возникнет хаос и это приводит к ошибкам ну а так все работает ровно и аккуратно