1 (2023-12-07 12:06:18 отредактировано Serg_)

Тема: SetUpdateCallback и обнуление стека Lua

Здравствуйте,

Раньше все работало, сейчас, как будто бы перестало.

Естественно использую LUA C API - для вызова SetUpdateCallback, вот такой просто С++ код:  да понимаю, что вероятность, что кто-то будет смтреть код стремится к нулю, поэтому срезюмирую поведение кода:

С помощью QLua C API:

-1:Я вызываю CreteDataSorce: вызов происходит успешно, мне возвращается таблица и нулевая ошибка.
-2:Я подтверждаю это проверкой стека Lua: на вершине стека находится таблица и нулевая ошибка.


-3:Затем я вызываю SetUpdateCallback и передаю вв него саму колбек функцию, которая будет вызыватся при каждой совершенной сделке.  Так же дополнительно я связываю по типу лямбды любое значение, чтбы предать для последующего ивзлечения его в самом колбеке.

-4:Вызыва SetUpdateCallback, убеждаюсь, что вызов SetUpdateCallback прошел успешно и опять проверяю стек на наличие ранее заказанной таблицы CreateDataSource - ОНИ НА МЕСТЕ!
.
-5: И наконец на рынке совершается сделка по заказанному инстурменту и вызывается колбек "my_callback__for__SetUpdateCallback". Все что я делаю в данном примере в этом колбеке это проверяю наличие моей таблицы CrateDataSourc в стеке Lua. ИИИИИИ ее там нет!!!! Весь стека кромер первого элемента был "кем-то" очищен!

ВОПРОС: КТО И ЗАЧЕМ очитстил стек ?? КАК видно из кода, между вызовов SetUpdateCallback и вызовом самой колбек-функции нет ни одной строчки кода, которая бы редактировала стек. Так что происходит тогда ?




lua_State* L_global;
int static nummer_table_from_stack;



void SetUpdateCallcak_wrapper(lua_State* L)
{

    L_global = L;
    std::cout << "L_global_adress:" << &L_global << std::endl;


    //-----------------------------------------------------------------1-Вызовем функцию CreateDataSource:Начало--------------------------------------------
    lua_getglobal(L, "CreateDataSource");                 

    lua_pushstring(L, "TQBR");       //Добавим первый параметр функции CreateDataSource на вершину стека
    lua_pushstring(L, "SBER");          //Добавим второй параметр функции CreateDataSource на вершину стека
    lua_pushnumber(L, 1);            //Добавим третий параметр функции CreateDataSource на вершину стека

    int status_lua_pcall = lua_pcall(L, 3, 2, 0);    //Так как все необходимые параметры добавлены в стек, то вызываем функцию lua_pcall - которая использя доабвенные параметры в правильном порядке - реализует вызов функции CreateDataSource: 2-ой параметр - это число аргументов, которые мы добаили в стек и которая принимает функция CreateDataSource; 2-ой: параметр - это число параметров, которое возвращает функция CreateDataSource. После успешного выполнения lua_pcall удаляет и значение функции и переданные аргменты со стека в кол-во указанном во втором параметре(не велючая функцию) и доабвляеи результат на стек в кол-во указанном во втором параметре.
    //-----------------------------------------------------------------1-Вызовем функцию CreateDataSource:Конец--------------------------------------------



    //-------------------------------------------------------------------5-Проверка на ошибку lua_pcall:Начало---------------------------------------------------------------------
    if (status_lua_pcall != 0)
    {
        //Ошибка произошла при вызове функции lua_pcall при вызове CreateDataSource:
        std::cout << "ERROR CreateDataSource" << std::endl;
        return;
    }
    //-------------------------------------------------------------------5-Проверка на ошибку lua_pcall:Конец---------------------------------------------------------------------
    else
    {

         nummer_table_from_stack = lua_gettop(L) - 1;   //Это номер элемента в стеке L - в котором теперь размещается полученная от CreateDataSource таблица. "-1" - потому что CreateDataSource поместила на вершину стека две перменные: таблицу и переменную об ошибке. То есть таблица находить на предпоследнем месте с вершины стека.

         my_call_SetUpdateCallback(L);     //Вызываем SetUpdateCallback wrapper
    }

}


l
static void ckeck_Lua_Stack(lua_State* L)
{

    std::cout << "----------------------------------------" << std::endl;

    int top = lua_gettop(L);
    std::cout << "Total element is stack:"<< top << std::endl;

    for (int i = 1; i <= top; i++) 
    {
        int type = lua_type(L, i);

        const char* type_name = lua_typename(L, type);

        std::cout << "type:" << type_name << ":";


        if (type == LUA_TSTRING || type == LUA_TNUMBER) 
        {
            std::cout << lua_tostring(L, i) << std::endl;
        }
        else
        {
            std::cout << std::endl;
        }
    }
    std::cout << "----------------------------------------" << std::endl << std::endl;


    //std::this_thread::sleep_for(std::chrono::milliseconds(100000));

}


static int my_callback__for__SetUpdateCallback(lua_State* L)
{

//Значит произошла сделка!

    std::cout << "Number_candle:"<< lua_tonumber(L, -1) << std::endl;

    ckeck_Lua_Stack(L_global);         //Проверяем стек Lua!!! И теперь в нем находится сдедующее:

----------------------------------------
Total element is stack:1                          //Куда черт возьми делать моя ранее заказанная таблица CreateDataSource ?????
type:number:1
----------------------------------------


    return 0;

}



static void my_call_SetUpdateCallback(lua_State* L)
{

    
    //--------------------------------------------------------
    lua_getfield(L_global, nummer_table_from_stack, "SetUpdateCallback");                       //"Извлекаем" из "таблицы" функцию SetUpdateCallback.
     
    lua_pushvalue(L_global, nummer_table_from_stack);                                                       //Помещаем копию обьекта таблицы CreateDataSource на вершину стека.
    //--------------------------------------------------------


    lua_pushnumber(L_global, 555);  //Просто для примера связываю какое то любое значение для передачи в колбек. 

    lua_pushcclosure(L_global, my_callback__for__SetUpdateCallback, 1);       //Захватываем.


    //--------------------------------------------------------
    int status_lua_pcall = lua_pcall(L_global, 2, 0, 0);                  //Реализауем вызов функции SetUpdateCallback с аргументом таблицы, которую поместили на вершину стека 
    //--------------------------------------------------------
    

    if (status_lua_pcall != 0)
    {
        std::cout << "lua_pcall__ERROR" << std::endl;
        return; 
    }
    else
    {
        std::cout << "SetUpdateCallback Success Call" << std::endl;
        
        ckeck_Lua_Stack(L_global);       //Проверяю что находится на данный момент в стеке Lua.

       //Находится следующее:

 ----------------------------------------
Total element is stack:3
type:string:1     //Таблица глобьальный функций
type:table:        //Это как раз запрошенная таблица CreateDataSource
type:nil:            //Ошибка при запросе таблицы CreateDataSource - то есть nil - ошибки нет.
----------------------------------------

        return;
    }


}

2 (2023-12-11 11:10:25 отредактировано swerg)

Re: SetUpdateCallback и обнуление стека Lua

Нашлось время почитать/вникнуть в ваше сообщение.

Похоже, вы исходите из ложного убеждения, что передаваемый вам стек Lua - это нечно глобальное и незыблемое.
Но это не так.
Не готов сейчас указать ссылку на документацию, но помнится такое читал где-то когда-то: стек формируется локально заново для каждого Си+вызова. Ну т.е. не обязательно каждый раз заново, но исходить надо из этого. В любом случае этот стек не является неким глобальным хранилищем, это лишь локальная структура для осуществления каждого отдельного Си-вызова.

Так что если что-то вам надо передавать из одной части кода в другую - то надо пользоваться либо глобальными переменными С++ для хранения, либо честно через Lua таблицу _G  (хранилище глобальных переменных Lua).

PS
Именно поэтому я категорически против написания логики роботов в виде Си-кода. Дело в том, что то, что просто и естественно выглядит в Lua-коде, при переложении на Си-код начинает выглядеть совершенно монтроидозно.