Синхронизация потоков в своей dll на с++

Страницы: 1
RSS
Синхронизация потоков в своей dll на с++
 
Добрый день. Перечитал старый форум, но внятного ответа так и не нашёл. Наверняка уже многие делали то же, что и я, и многие ещё будут делать. Поэтому хочу уточнить один важный момент.
Есть Lua - скрипт, в котором подключается своя библиотека на c++. В этой библиотеке создаётся несколько потоков.Например, 1 поток будет отправлять заявки в Quik, другой поток будет читать таблицу параметров, ещё несколько потоков будут подписываться на ТВС и перебирать все сделки через CreateDataSource (а их может быть миллионы). В общем каждый поток будет одновременно запускать какие-то Lua-функции. А Lua - стек у нас только один. Вопрос:
нужно ли синхронизировать эти потоки и гарантировать вызов lua функций из dll в одно время только однажды ? Если да, то получается, что пока какой-то поток, например перебирает все сделки в цикле (миллион), то заявки отправлять нельзя ? Параметры читать нельзя ? Все задачи будут ждать завершения какого-то одного потока ? А если нужно одновременно в разных потоках вызвать CreateDataSource, каждый со своим инструментом, и одновременно их записывать в какие-либо массивы ?
 
тема многопоточности, а тем более многопоточности в QLUA - тянет на целую книгу. в одном топике - вам тут никто не ответит на весь список ваших вопросов. Для начала, почитайте вот этот форум: quik2dde.ru. После того, как ВЕСЬ! его прочитаете - прочитайте ещё раза 2.

Цитата
Дмитрий пишет:
Перечитал старый форум, но внятного ответа так и не нашёл.
а потому что его и нет))) внятный ответ должны дать Вы сами, бо как изначально, LUA задумывалась, как однопоточная, потом к ней добавили корутины, дочерние состояния (child lua_State) и пр.
Цитата
Дмитрий пишет:
Наверняка уже многие делали то же, что и я, и многие ещё будут делать.
увы, таких единицы, если считать, чтоб всё ещё СТАБИЛЬНО работало. Дело в том, что сама QLUA постоянно меняется и постоянно допиливается. поэтому, пока не будет нормальной/стабильной "базы" - все наши "устремления" - лишь жалкие поделки, особенно, принимая во внимание изначальную полную "сопливость" штатной дкументации по QLUA.
 
Цитата
Дмитрий пишет:
Добрый день. Перечитал старый форум, но внятного ответа так и не нашёл. Наверняка уже многие делали то же, что и я, и многие ещё будут делать. Поэтому хочу уточнить один важный момент.
Есть Lua - скрипт, в котором подключается своя библиотека на c++. В этой библиотеке создаётся несколько потоков.Например, 1 поток будет отправлять заявки в Quik, другой поток будет читать таблицу параметров, ещё несколько потоков будут подписываться на ТВС и перебирать все сделки через CreateDataSource (а их может быть миллионы). В общем каждый поток будет одновременно запускать какие-то Lua-функции. А Lua - стек у нас только один. Вопрос:
нужно ли синхронизировать эти потоки и гарантировать вызов lua функций из dll в одно время только однажды ? Если да, то получается, что пока какой-то поток, например перебирает все сделки в цикле (миллион), то заявки отправлять нельзя ? Параметры читать нельзя ? Все задачи будут ждать завершения какого-то одного потока ? А если нужно одновременно в разных потоках вызвать CreateDataSource, каждый со своим инструментом, и одновременно их записывать в какие-либо массивы ?
Добрый день.
Я бы настоятельно советовал Вам посмотреть в сторону coroutine в Lua. Уверен, что их возможности полностью покроют описанные Вами задачи.
Но если желание наплодить потоков в своей библиотеке непреодолимо, то рекомендации ниже:
1. Линкуйте свою библиотеку с qlua.dll
2. Если пункт два вызывает вопросы, то убедитесь что в папке с терминалом (там же, где лежит info.exe и qlua.dll) присутствует файл lua5.1.dll собранный нами. Проверить это можно в свойствах файла:


3.Для каждого отдельного потока, который работает с Lua перед его запуском необходимо проделать примерно следующее:

Код
 DWORD WINAPI myThread(LPVOID param) 
{    
   lua_State *L = (lua_State*)param;  
   ....  
   return 0;
}   
... 
//вот тут формируется новый стек Lua для потока
lua_gc(L, LUA_GCSTOP, 0);  
thread_L_stack = lua_newthread(L); 
thread_L_ref = luaL_ref( callbackCode, LUA_REGISTRYINDEX); 
lua_pushvalue(callbackCode, -1);  
lua_gc(L, LUA_GCRESTART, 0);  
...    
CreateThread(NULL, 0, myThread, (LPVOID) tread_L_stack, 0, NULL);

4. При завершении работы поток не должен вызывать lua_close(thread_L), это приводит к закрытию всей Lua для скрипта.
5. для того чтобы сборщик мусора при завершении все корректно убрал необходимо сделать:
Код
lua_unref(L, thread_L_ref);
Вроде все.
Но я бы все таки настоятельно рекомендовал использовать Lua coroutine
 
Michael Bulychev

К Вам предложение, дополнить на общеизвестном форуме соответствующие темы, а также написать больше примеров того, как добавлять из C++ новые функции через closure.
 
Цитата
sam063rus пишет:
как добавлять из C++ новые функции через closure.
Поясните свою мысль? Для чего это?
 
но ведь именно так вы регистрируете в qlua свои функции?
 
Нет
 
)))тогда другой вопрос: а как?)))
 
Код
#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) 

 
ладно. не хотите говорить - не надо.
 
Michael Bulychev

получается, если верить Вашим словам - то у Вас должно быть так:
#define lua_register(L,n,f) (lua_pushcfunction(L, (getNumberOf)), lua_setglobal(L, ("getNumberOf")))
 
Цитата
sam063rus пишет:
Michael Bulychev

получается, если верить Вашим словам - то у Вас должно быть так:
#define lua_register(L,n,f) (lua_pushcfunction(L, (getNumberOf)), lua_setglobal(L, ("getNumberOf" ;) ))
Примерно так и есть
 
Цитата
sam063rus пишет:
Michael Bulychev

получается, если верить Вашим словам - то у Вас должно быть так:
#define lua_register(L,n,f) (lua_pushcfunction(L, (getNumberOf)), lua_setglobal(L, ("getNumberOf"  ;)  ))
отсюда, разворачиваем макросы, получаем:
#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)

т.е.  в итоге:

lua_pushcclosure(L, getNumberOf)
lua_setfield(L, GLOBALSINDEX, "getNumberOf"


вот про это я и спрашиваю. Почему именно lua_pushcclosure?
 
просто для меня понятия: просто функция и closure - несколько различаются.
 
Можно считать, что "обычная" C-функция является частным случаем C closure, у которой нет upvalues.
 
Цитата
Michael Bulychev пишет:
Можно считать, что "обычная" C-функция является частным случаем C closure, у которой нет upvalues.
да. уже прочитал: http://www.lua.org/pil/27.3.3.html
 
Спасибо. Буду думать как лучше сделать.
 
По поводу *coroutine* вопрос. В руководстве по Люа coroutine описывается как средство создания многопоточной среды. В данном случае многопоточность означает одновременное исполнение в двух потоках или это о другом?
 
имеется ввиду не потоки операционной сисиемы, а псевдомногопочность на основе LUA. Почитайте здесь:
http://quik2dde.ru/viewtopic.php?id=131
http://quik2dde.ru/viewtopic.php?id=130
 
Дмитрий,
1) Вот здесь:
"ещё несколько потоков будут подписываться на ТВС и перебирать все сделки через CreateDataSource (а их может быть миллионы). "
У Вас огромные резервы в повышении производительности.
Рекомендую полностью пересмотреть Вашу концепцию  обработки информации.
-----------------------------------------------
2) Следует учитывать что сораунды не позволяют задействовать множество ядер в процессоре  или множество процессоров в кластере.
Они позволяют переключаться лишь между фрагментами алгоритма в рамках одного ядра.
 
lergen, корутины работают по принципу кооперативной многопоточности, то есть пока один поток явно не отдаст управление, другой не продолжит свое выполнение. Фактически работает один поток с переключением на разные точки исполнения программы.
 
Цитата
Constantin Constantin пишет:
lergen , корутины работают по принципу кооперативной многопоточности, то есть пока один поток явно не отдаст управление, другой не продолжит свое выполнение. Фактически работает один поток с переключением на разные точки исполнения программы.
Ок спасибо понятно. Похоже что реально многопоточность можно получить только разделив функции между разными скриптами.
 
Цитата
lergen пишет:
Похоже что реально многопоточность можно получить только разделив функции между разными скриптами.
в самом простом случае - Да.

И даже это нельзя будет назвать истинной многопоточностью - потому что квик работает с одним потоком данных и остальные скрипты просто будут ждать своей очереди для доступа к нему.
 
Цитата
lergen пишет:
Ок спасибо понятно. Похоже что реально многопоточность можно получить только разделив функции между разными скриптами.
Параллельно будет работать только код в main. Все колбаки вызываются в основном потоке Квика.
 
Цитата
Constantin Constantin пишет:
Цитата
lergen пишет:
Ок спасибо понятно. Похоже что реально многопоточность можно получить только разделив функции между разными скриптами.
Параллельно будет работать только код в main. Все колбаки вызываются в основном потоке Квика.
Ну хотя бы так.
 
Добрый день,
Добавлю свой стакан бензина в костер дискуссии.
--------------------------
Есть как минимум два варианта
1) несколько скриптов с обменом информацией между скриптами
2) несколько потоков и один из них main с дополнительной синхронизацией потоков
----------------------------
Хотя поток входных данных с сервера один, но это не мешает сделать параллельную обработку,
так как обработка данных умным роботом требует значительных ресурсов.
А обработку по разным инструментам можно делать параллельно без проблем.
-------------------------------
Из собственного опыта замечу,
что в QUIKe на существующем уровне реализуются оба способа( реализовал год назад оба)
 
Цитата
Michael Bulychev пишет:
Цитата
Дмитрий пишет:
Добрый день. Перечитал старый форум, но внятного ответа так и не нашёл. Наверняка уже многие делали то же, что и я, и многие ещё будут делать. Поэтому хочу уточнить один важный момент.
Есть Lua - скрипт, в котором подключается своя библиотека на c++. В этой библиотеке создаётся несколько потоков.Например, 1 поток будет отправлять заявки в Quik, другой поток будет читать таблицу параметров, ещё несколько потоков будут подписываться на ТВС и перебирать все сделки через CreateDataSource (а их может быть миллионы). В общем каждый поток будет одновременно запускать какие-то Lua-функции. А Lua - стек у нас только один. Вопрос:
нужно ли синхронизировать эти потоки и гарантировать вызов lua функций из dll в одно время только однажды ? Если да, то получается, что пока какой-то поток, например перебирает все сделки в цикле (миллион), то заявки отправлять нельзя ? Параметры читать нельзя ? Все задачи будут ждать завершения какого-то одного потока ? А если нужно одновременно в разных потоках вызвать CreateDataSource, каждый со своим инструментом, и одновременно их записывать в какие-либо массивы ?
Добрый день.
Я бы настоятельно советовал Вам посмотреть в сторону coroutine в Lua. Уверен, что их возможности полностью покроют описанные Вами задачи.
Но если желание наплодить потоков в своей библиотеке непреодолимо, то рекомендации ниже:
1. Линкуйте свою библиотеку с qlua.dll
2. Если пункт два вызывает вопросы, то убедитесь что в папке с терминалом (там же, где лежит info.exe и qlua.dll) присутствует файл lua5.1.dll собранный нами. Проверить это можно в свойствах файла:


3.Для каждого отдельного потока, который работает с Lua перед его запуском необходимо проделать примерно следующее:
Код
   DWORD WINAPI myThread(LPVOID param) 
{    
   lua_State  * L  =  (lua_State * )param;  
    ..  ..   
    return   0 ;
}   
 .. . 
//вот тут формируется новый стек Lua для потока
lua_gc(L, LUA_GCSTOP,  0 );  
thread_L_stack  =  lua_newthread(L); 
thread_L_ref  =  luaL_ref( callbackCode, LUA_REGISTRYINDEX); 
lua_pushvalue(callbackCode,  -  1 );  
lua_gc(L, LUA_GCRESTART,  0 );  
 .. .    
CreateThread(NULL,  0 , myThread, (LPVOID) tread_L_stack,  0 , NULL);

  
4. При завершении работы поток не должен вызывать lua_close(thread_L), это приводит к закрытию всей Lua для скрипта.
5. для того чтобы сборщик мусора при завершении все корректно убрал необходимо сделать:
Код
  lua_unref(L, thread_L_ref);  
Вроде все.
Но я бы все таки настоятельно рекомендовал использовать Lua coroutine
А что такое в коде "callbackCode" ?
По описанию функции там должен быть  lua_State. Какой подставлять - L или thread_L_stack ?

И можно ли при завершении потока делать thread_L_stack в самОм новом-созданном потоке, т.е. внутри функции потока myThread(LPVOID param)  ?
 
В последнем вопросе имелось ввиду:
Можно ли при завершении потока делать lua_unref(L, thread_L_ref);  в самОм новом-созданном потоке, т.е. внутри функции потока myThread(LPVOID param) ?
Страницы: 1
Читают тему (гостей: 1)
Наверх