quik 64 вызов функции lua из dll c++

Страницы: 1
RSS
quik 64 вызов функции lua из dll c++
 
В 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 в цикле, который выполнится неизвестно сколько раз. Сколько значений вы выдернули в итоге из основного стека в новый? При этом основной поток продолжает работать параллельно и что-то там пихает в свой стек, а вы у него из-под носа это выдергиваете. И т.д. и т.п.
 
в с++ я не силен познакомился в первые ну хорошо попробуем так
Код
static int forLua_runMAIN1(lua_State* L)
{  
    lua_State* L1 = lua_newthread(L);
    lua_getglobal(L1, "main1");
    lua_pcall(L1, 0, 0, 0);   
    return (0); 
}

получилось? это в 32 бит версии могло такое прокатить

 
Цитата
Алексей написал:
в с++ я не силен познакомился в первые ну хорошо попробуем так
Код
  static int forLua_runMAIN1(lua_State *  L)
{  
    lua_State *  L1  =  lua_newthread(L);
    lua_getglobal(L1,  "main1" );
    lua_pcall(L1,  0 ,  0 ,  0 );   
     return  ( 0 ); 
}
  
 получилось? это в 32 бит версии могло такое прокатить  
и это я отбросил все условия предположил что main у меня в бесконечном цикле к примеру а в main1 функции скрипта стоит одна строка message("не получается")  и все равно вы ее не запустите с t1
 
Цитата
Алексей написал:
Код
static int forLua_runMAIN1(lua_State* L)
{  
    lua_State* L1 = lua_newthread(L);
    lua_getglobal(L1, "main1");
    lua_pcall(L1, 0, 0, 0);   
    return (0); 
}
А теперь объясните, пожалуйста, словами, что в этой функции происходит, построчно. То есть что как вы думаете происходит.
 
кажется дошло до меня (1 Создает новый поток, толкает его в стек и возвращает указатель на lua_State, который представляет этот новый поток.) уже повод призадуматься буду углубляться в знания значит Спасибо)
 
Цитата
Алексей написал:
(1 Создает новый поток, толкает его в стек и возвращает указатель на lua_State, который представляет этот новый поток.
Таки нет, оно вообще никакой поток не создает. Оно создает стейт для нового потока, и вы когда с ним вызываете lua_pcall, вы выполняете вызываемую функцию в том же самом потоке, только в другом стейте. Вам надо этот стейт передать теперь новому нативному потоку (а не основной стейт, как у вас было). Основной стейт из нового потока вообще трогать нельзя.
 
Вот и снова наступил свободный денек,решил добить данную тему, даю вам ссылку кто еще не понял в каком направлении двигаться https://qarchive.ru/198607_ekvivalent_lua_coroutine_create_v_s___s_ispol_zova­niem_lua_newthread да и спасибо Anton помог немного))
 
Цитата
Алексей написал:
помог немного))
Ну раз немного помогло, давайте продвинемся еще
Код
#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() то возникнет хаос и это приводит к ошибкам ну а так все работает ровно и аккуратно
 
Цитата
 
Цитата
Алексей написал:
join() выступает как электронное табло в сбербанке
Конгениально.
Страницы: 1
Читают тему
Наверх