<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
	<channel>
		<title>Форум QUIK [тема: Потоковая безопасность в QLua - документация и реальность]</title>
		<link>http://forum.quik.ru</link>
		<description>Новое в теме Потоковая безопасность в QLua - документация и реальность форума  на сайте Форум QUIK [forum.quik.ru]</description>
		<language>ru</language>
		<docs>http://backend.userland.com/rss2</docs>
		<pubDate>Wed, 20 May 2026 15:37:27 +0300</pubDate>
		<item>
			<title>Потоковая безопасность в QLua - документация и реальность</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message35257/topic3270/">Потоковая безопасность в QLua - документация и реальность</a></b> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			У разработчиков на этот счет &nbsp;<noindex><a href="https://forum.quik.ru/messages/forum10/message20519/topic2200/#message20519" target="_blank" rel="nofollow">другое мнение</a></noindex> :<br /><br /> <br />====quote====<br /><noindex><a href="/user/17/" target="_blank" rel="nofollow">Sergey Gorokhov</a></noindex> написал:<br /> &nbsp;<br />====quote====<br /> <noindex><a href="/user/54/" target="_blank" rel="nofollow">Старатель</a></noindex> &nbsp;написал:<br />Вопрос разработчикам: верно ли, что в QUIK, как таковой, многопоточности нет? <br />=============<br />В QUIK есть многопоточность<br /> &nbsp;<br />====quote====<br /> <noindex><a href="/user/54/" target="_blank" rel="nofollow">Старатель</a></noindex> &nbsp;написал:<br />Да, есть два потока: основной и main. Но в каждый момент времени работают команды только из одного потока. Просто происходит переключение между потоками на уровне ОС.<br />=============<br />так обрабатывается ситуация при одновременном доступе к одному ресурсу<br />=============<br />Как раз собственно интерпретатор Lua и является таким ресурсом, которым не получатеся воспользоваться из нескольких потоков одновременно. &nbsp;Возможно не все разработчики об этом знают, смотрите в код Lua - так надежнее... <br />
			<i>09.12.2018 15:45:00, kroki.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message35257/topic3270/</link>
			<guid>http://forum.quik.ru/messages/forum10/message35257/topic3270/</guid>
			<pubDate>Sun, 09 Dec 2018 15:45:00 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Потоковая безопасность в QLua - документация и реальность</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message35247/topic3270/">Потоковая безопасность в QLua - документация и реальность</a></b> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			Интересно, что в обработчике OnInit или BODY код, помещенный в ssort, также работает быстрее, хотя main на этом этапе ещё не включается в работу. <br />
			<i>09.12.2018 10:21:58, Старатель.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message35247/topic3270/</link>
			<guid>http://forum.quik.ru/messages/forum10/message35247/topic3270/</guid>
			<pubDate>Sun, 09 Dec 2018 10:21:58 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Потоковая безопасность в QLua - документация и реальность</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message35244/topic3270/">Потоковая безопасность в QLua - документация и реальность</a></b> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			<br />====quote====<br /><a class="blog-p-user-name" id="bp_cEq4rB3Z" href="/user/9815/" bx-tooltip-user-id="9815">kroki</a> написал:<br />Вообще производительность Lua при заданных макросах &nbsp;lua_lock() / lua_unlock() &nbsp;просто ужасная, почти на каждом шагу освобождение и захват блокировки.<br /><br />=============<br /><noindex><a href="https://forum.quik.ru/messages/forum10/message19460/topic2200/#message19460" target="_blank" rel="nofollow">Здесь</a></noindex> я обращал на это внимание.<br /><br /><br />====quote====<br /><a class="blog-p-user-name" id="bp_cFx6yt4A" href="/user/9815/" bx-tooltip-user-id="9815">kroki</a> написал:<br />Поэтому у себя обернул все критические callbacks в &nbsp;table.ssort() , чтобы не было постоянной борьбы за блокировку с &nbsp;main().<br /><br />=============<br /><br />====quote====<br /><a class="blog-p-user-name" id="bp_ckLSGy19" href="/user/9815/" bx-tooltip-user-id="9815">kroki</a> написал:<br />Но можно использовать для создания &quot;критических секций&quot;, то есть вызова произвольних функций при удерживаемой блокировке: 
====code====
<pre>&nbsp;&nbsp; table.ssort ({&nbsp;&nbsp;0 ,&nbsp;&nbsp;0&nbsp;&nbsp;},&nbsp;&nbsp;function ()
&nbsp;&nbsp;&nbsp;&nbsp;-- код здесь выполняется под блокировкой 
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;&nbsp; true 
 end )</pre>
=============
<br />=============<br />Интересная идея. Возьму на вооружение.<br />Код, действительно, внутри ssort выполняется быстрее. Но все же в два раза дольше, чем в чистом Lua.<br /><br /><br />====quote====<br /><a class="blog-p-user-name" id="bp_gDope04s" href="/user/9815/" bx-tooltip-user-id="9815">kroki</a> написал:<br />хотя &quot;потоки&quot; - это настояшие потоки операционной системы, в каждый момент времени интерпретатор Lua работает только в одном потоке, параллельной работы интерпретаторов нет.<br />=============<br /><br />У разработчиков на этот счет <noindex><a href="https://forum.quik.ru/messages/forum10/message20519/topic2200/#message20519" target="_blank" rel="nofollow">другое мнение</a></noindex>:<br /><br /><br />====quote====<br /><a class="blog-p-user-name" id="bp_R7PqCdbQ" href="/user/17/" bx-tooltip-user-id="17">Sergey Gorokhov</a> написал:<br /> <br />====quote====<br /><noindex><a href="/user/54/" target="_blank" rel="nofollow">Старатель</a></noindex> написал:<br />Вопрос разработчикам: верно ли, что в QUIK, как таковой, многопоточности нет? <br />=============<br /> В QUIK есть многопоточность<br /> <br />====quote====<br /><noindex><a href="/user/54/" target="_blank" rel="nofollow">Старатель</a></noindex> написал:<br />Да, есть два потока: основной и main. Но в каждый момент времени работают команды только из одного потока. Просто происходит переключение между потоками на уровне ОС.<br />=============<br /> так обрабатывается ситуация при одновременном доступе к одному ресурсу<br />=============<br /> <br />
			<i>09.12.2018 02:43:28, Старатель.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message35244/topic3270/</link>
			<guid>http://forum.quik.ru/messages/forum10/message35244/topic3270/</guid>
			<pubDate>Sun, 09 Dec 2018 02:43:28 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Потоковая безопасность в QLua - документация и реальность</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message28314/topic3270/">Потоковая безопасность в QLua - документация и реальность</a></b> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			Стал программировать, руководствуясь своей &quot;докой&quot; выше, и уперся в противоречие: с одной стороны утверждаю, что <B>GC</B> всегда работает при удерживаемой блокировке (что правда), с другой стороны <B>collectgarbage()</B> - функция стандартной библиотеки Lua, и я написал, что таковые работают не через <B>Lua C API</B>, и потому не потокобезопасны.<br /><br />Так вот последнее было не верно: пункт <B>6</B> меняем на:<br /><br /><B>6.</B> Функции стандартной библиотеки Lua (такие, как <B>table.sort</B>) являются &quot;Си&quot; функциями.<br /><br />Точка. &nbsp;То есть как и остальные &quot;Си&quot; функции они работают через <B>Lua C API</B>, который делает <B>lua_lock()</B>/<B>lua_unlock()</B> в нужных местах. &nbsp;Но их работа не атомарна. &nbsp;Например, реализация <B>table.concat()</B> делает (на Си)
====code====
<pre>&nbsp;&nbsp;&nbsp;&nbsp;static int tconcat (lua_State *L) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;luaL_Buffer b;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;size_t lsep;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int i, last;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const char *sep = luaL_optlstring(L, 2, "", &#38;lsep);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;luaL_checktype(L, 1, LUA_TTABLE);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i = luaL_optint(L, 3, 1);
A:&nbsp;&nbsp;&nbsp;&nbsp;last = luaL_opt(L, luaL_checkint, 4, luaL_getn(L, 1));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;luaL_buffinit(L, &#38;b);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (; i &#60;= last; i++) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lua_rawgeti(L, 1, i);
B:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;luaL_argcheck(L, lua_isstring(L, -1), 1, "table contains non-strings");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;luaL_addvalue(&#38;b);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (i != last)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;luaL_addlstring(&#38;b, sep, lsep);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;luaL_pushresult(&#38;b);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;
&nbsp;&nbsp;&nbsp;&nbsp;}
</pre>
=============
то есть в строке <B>A</B> запоминает количество элементов, а в строке <B>B</B> проверяется, что очередной элемент - строка. &nbsp;Но блокировка захватывается только на время вызова функций <B>Lua C API</B> (например, <B>lua_rawgeti()</B> в коде выше - Михаил как раз об этом и писал), а во время собственно работы цикла не удерживается. &nbsp;Это значит, что другой поток может удалить какие-то элементы из массива, сделав его короче, но код все еще помнит старый размер, и тогда на очередной итерации цикл вытащит <B>nil</B>, и проверка типа &quot;строка&quot; бросит исключение &quot;table contains non-strings&quot;.<br /><br />То есть обертка <B>table.sconcat()</B> нужна для обеспечения атомарности работы (потокобезопасность в строгом смысле уже была и в оригинальной функции).<br /><br />Вообще производительность Lua при заданных макросах <B>lua_lock()</B>/<B>lua_unlock()</B> просто ужасная, почти на каждом шагу освобождение и захват блокировки. &nbsp;Поэтому у себя обернул все критические callbacks в <B>table.ssort()</B>, чтобы не было постоянной борьбы за блокировку с <B>main()</B>. &nbsp;Кстати, в некоторых старых версиях Quik (например, 7.5.0.72) все callbacks вызывались при удержанной блокирокве, но в 7.14.1.7 это уже не так.<br /><br />Ниже тест &quot;многопоточной&quot; скорости выполнения. &nbsp;Если запустить скрипт и дождаться окончания работы, но борьбы за блокировку нет. &nbsp;Если же запустить скрипт и тут же нажать кнопку &quot;Остановить&quot;, то будет борьба, и время выпонения цикла в <B>main()</B> существенно возрастет:
====code====
<pre>local total = 100000000

function OnStop()
&nbsp;&nbsp; local var
&nbsp;&nbsp; for i = 1, total do
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var = i
&nbsp;&nbsp; end

&nbsp;&nbsp; return 15000
end

function main()
&nbsp;&nbsp; local start = os.clock()

&nbsp;&nbsp; local var
&nbsp;&nbsp; for i = 1, total do
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var = i
&nbsp;&nbsp; end

&nbsp;&nbsp; local elapsed = os.clock() - start
&nbsp;&nbsp; message("CPU time: "..elapsed)
end
</pre>
============= <br />
			<i>19.12.2017 16:28:17, kroki.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message28314/topic3270/</link>
			<guid>http://forum.quik.ru/messages/forum10/message28314/topic3270/</guid>
			<pubDate>Tue, 19 Dec 2017 16:28:17 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Потоковая безопасность в QLua - документация и реальность</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message28265/topic3270/">Потоковая безопасность в QLua - документация и реальность</a></b> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			Сегодня сделал несколько тестов и просмотрел код Lua, и наконец понял. &nbsp;Быть может будет полезно кому-то еще (ну и чтобы закрыть ветку):<br /><br /><B>0.</B> В реализации Lua есть макросы <B>lua_lock()</B> и <B>lua_unlock()</B>, которые вызываются в коде Lua в нужных местах, но по умолчанию ничего не делают. &nbsp;QLua переопределяет эти макросы как вызовы <B>EnterCriticalSection()</B> и <B>LeaveCriticalSection()</B> - захват и освобождние <I>рекурсивной</I> блокировки (сам Lua рекурсивности не требует, но она нужна для реализации <B>table.ssort()</B>).<br /><br /><B>1.</B> Перед запуском Lua программы реализация Lua делает вызов <B>lua_lock()</B>, то есть <I>инструкции Lua программы выполняются при удерживаемой блокировке</I>. &nbsp;Это значит, что хотя &quot;потоки&quot; - это настояшие потоки операционной системы, в каждый момент времени <I>интерпретатор Lua</I> работает только в одном потоке, параллельной работы интерпретаторов нет.<br /><br /><B>2.</B> После некоторых инструкий Lua программы интерпретатор делает
====code====
<pre>lua_unlock();
lua_lock();</pre>
=============
то есть блокировка освобождается и тут же делается попытка захватить ее назад, но если другой поток ожидал блокировку, то он ее захватит первым и будет выполняться до тех пор, пока сам не сделает
====code====
<pre>lua_unlock();
lua_lock();</pre>
=============
(или не вызовет &quot;Си&quot; функцию - смотрим ниже) во время чего первый поток сможет захватить блокировку опять, и т.д.<br /><br /><B>3.</B> <B>Garbage collector</B> всегда вызывается при удерживаемой блокировке.<br /><br /><B>4.</B> Вызов &quot;Си&quot; функции из Lua программы (то есть функции, написанной не на Lua, а на каком-то другом языке) выполняется так:
====code====
<pre>lua_unlock();
call external С function;
lua_lock();</pre>
=============
То есть <I>&quot;Си&quot; функции выполняются без удержания блокировки</I>.<br /><br /><B>5.</B> Все функции <noindex><a href="http://www.lua.org/manual/5.1/manual.html#3" target="_blank" rel="nofollow"><B>Lua C API</B></a></noindex> (то есть те, которые могут вызываться из &quot;Си&quot; функций) - потокобезопасные, то есть делают <B>lua_lock()</B>/<B>lua_unlock()</B> где это необходимо.<br /><br /><B>6.</B> Функции стандартной библиотеки Lua (такие, как <B>table.sort</B>) являются &quot;Си&quot; функциями, но <B>не</B> работают через <B>Lua C API</B> (дергают внутренний код напрямую) и <B>не</B> делают <B>lua_lock()</B>/<B>lua_unlock()</B> - то есть не являются потокобезопасными. Именно поэтому в QLua добавлены потокобезопасные аналоги некоторых функций, которые просто оборачивают своих младших братьев в <B>lua_lock()</B>/<B>lua_unlock()</B>.<br /><br /><br />Теперь переводим документацию:<br /><br />====quote====<br />Одновременная работа с таблицами из функций обратного вызова скрипта и функции main() может приводить к неопределенным ситуациям.<br />=============<br />следует читать<br />====quote====<br />Одновременная работа с таблицами <I><B>с использованием функций стандартной библиотеки Lua</B></I> из функций обратного вызова скрипта и функции main() может приводить к неопределенным ситуациям.<br />=============<br />То есть, функциями <B>table.sort</B>, <B>unpack</B> и т.п. работать с таблицей (потенциально) одновременно из разных потоков нельзя (нужно использовать потокобезопасные замены). &nbsp;Но вот просто код Lua выполнять можно, то есть можно писать
====code====
<pre>shared_table&#91;key&#93; = val
global_var = nil
</pre>
=============
и т.п. - здесь функции библитотеки не задействованы, а инструкции программы Lua выполняются с удержанием блокировки. &nbsp;Также можно использовать &quot;Си&quot; функции сторонних библиотек - они работают через <B>Lua C API</B>, а, значит, потокобезопасны. &nbsp;Только не нужно путать потоковую безопасность и атомарность: если &quot;Си&quot; функция обещает вставить в какую-то таблицу 5 элементов, вполне возможно, что другой поток увидит, что пока вставлено только 3 элемента.<br /><br /><br />====quote====<br />Выполнение потокобезопасной функции блокирует выполнение кода в другом потоке до окончания работы функции.<br />=============<br />следует читать<br />====quote====<br />Выполнение потокобезопасной функции блокирует выполнение <I><B>Lua</B></I> кода в другом потоке до окончания работы функции.<br />=============<br />То есть, потокобезопасная функция удерживает блокировку и не дает ее другому интерпретатору, но если в другом потоке уже началось выполнение &quot;Си&quot; функции, то оно продолжится либо до завершения, либо до первого вызова <B>Lua C API</B>, и только тогда будет сделана попытка захватить блокировку.<br /><br /><br />Дальше сам себе отвечаю:<br /><br />====quote====<br /><B>Вопрос 1:</B> приводит ли присвоение <B>nil</B> глобальным переменным из функции <B>main()</B> (то есть не главного потока) к неопределенным ситуациям?<br />=============<br />Нет, присвоение делается кодом Lua, то есть под блокировкой.<br /><br /><br />====quote====<br /><B>Вопрос 2:</B> имеется ввиду, что другие потоки блокируются при попытке вызвать (ту же или какую-то другую) потокобезопасную функцию (классическая <B>critical section</B>)? Или же вообще все потоки волшебным образом останавливаются, ну, так, &quot;на всякий случай&quot;? :)<br />=============<br />Блокируется интерпретатор Lua в другом потоке при попытке выполнть следующую инструкцию (либо &quot;Си&quot; функция при попытке вызвать <B>Lua C API</B>).<br /><br /><br />====quote====<br /><B>Вопрос 3:</B> как вообще тогда использовать table.ssort()?<br />=============<br />По назначению - никак. &nbsp;Но можно использовать для создания &quot;критических секций&quot;, то есть вызова произвольних функций при удерживаемой блокировке:
====code====
<pre>table.ssort({ 0, 0 }, function()
&nbsp;&nbsp; -- код здесь выполняется под блокировкой
&nbsp;&nbsp; return true
end)</pre>
=============
Только не забываем, что <B>table.ssort()</B> &quot;виснет&quot;, если в функции сравнения возникает ошибка (проверял на Quik 7.14.1.7):
====code====
<pre>function main()
&nbsp;&nbsp;table.ssort({ 1, "a" })
end</pre>
=============
Поэтому в нужных местах используем <B>pcall()</B>.<br /><br /><br />====quote====<br /><B>Вопрос 4:</B> в примере выше, что произойдет, если один поток изменит таблицу потокобезопасной функцией как раз в то время, когда другой поток находится где-то в дебрях интерпретатора Lua (внутри <B>ipairs()</B>, <B>t[key]</B>, или еще где)? Что именно сделано, чтобы все не &quot;взорвалось&quot;? Или &quot;так делать нельзя&quot;? <br />=============<br /><B>ipairs()</B> является функцией стандартной библиотеки Lua и не является потокобезопасной - &quot;так делать нельзя&quot;. &nbsp;Lua код <B>t[key]</B> будет выполнен с удержанием той же блокировки, которая используется в потокобезопасной функции, так что выполнится или до, или после такой функции, но никак не одновременно - все будет безопасно.<br /><br /><br />====quote====<br /><B>Вопрос 5:</B> а какие &quot;сообщения&quot; можно посылать таким образом? Абсолютно любые &quot;типы&quot; Lua, или есть ограничения? Этот вопрос связан со следующим:<br />=============<br />Абсолютно любые типы Lua.<br /><br /><br />====quote====<br /><B>Вопрос 6:</B> а как потоки дружат со сборщиком мусора (<B>garbage collector</B>)? Он один на все потоки, или по одному на каждый? Если один, то в каком потоке выполняется, и что именно сделано, чтобы <B>GC</B> в одном потоке не &quot;взорвал&quot; другой работающий поток, и не &quot;взорвался&quot; сам, считая свободной память, которую другой поток как раз начинает использовать)? Если же <B>GC</B> у каждого потока свой, то в случае <B>message passing</B> как в примере выше как именно передается <B>ownership</B> (то есть чей <B>GC</B> отвечает за рекламацию сообщения)?<br />=============<br /><B>GC</B> может запуститься в любом потоке, но при удерживаемой блокировке. &nbsp;Поскольку настоящей параллельной работы интерпретаторов Lua не бывает, то <B>GC</B> работает точно так же, как и в случае обычных сопроцедур Lua (<B>coroutines</B>) в одном потоке: никаких раздельных <B>ownership</B> нет, <B>GC</B> проводит рекламацию объектов в <B>environments</B> обоих потоков (а второй интерпретатор ждет освобождения блокировки) - все безопасно. <br />
			<i>17.12.2017 21:40:58, kroki.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message28265/topic3270/</link>
			<guid>http://forum.quik.ru/messages/forum10/message28265/topic3270/</guid>
			<pubDate>Sun, 17 Dec 2017 21:40:58 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Потоковая безопасность в QLua - документация и реальность</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message28230/topic3270/">Потоковая безопасность в QLua - документация и реальность</a></b> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			<br />====quote====<br /><br />Если не трудно, то все же скажите, как, и как именно &quot;блокируются&quot; потоки в &nbsp;table.sconcat() &nbsp;- это все хочется знать, чтобы понимать, как именно лучше писать Lua код, какая операция сколько стоит... &nbsp;<br /><br />=============<br />в оригинальной версии table.concat, насколько я помню, блокировка происходит в момент получения элемента таблицы. В sconcat блокировка происходит на время выполнения всего цикла.<br /><br /><br />====quote====<br /><br />Теперь, например, стало ясно, что в начале скрипта нужно писать<br />
====code====
<pre>&nbsp;&nbsp; local&nbsp;&nbsp;string, table, pairs, ipairs&nbsp;&nbsp;=&nbsp;&nbsp;string, table, pairs, ipairs&nbsp;&nbsp;</pre>
=============
и т.д., чтобы не лочить &nbsp;global environment &nbsp;при каждом доступе к &nbsp;string.something() &nbsp;и т.д.<br /><br />=============<br />Это делается для ускорения обращения к нужным данным и не связано с блокировками. <br />
			<i>15.12.2017 08:43:00, Michael Bulychev.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message28230/topic3270/</link>
			<guid>http://forum.quik.ru/messages/forum10/message28230/topic3270/</guid>
			<pubDate>Fri, 15 Dec 2017 08:43:00 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Потоковая безопасность в QLua - документация и реальность</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message28228/topic3270/">Потоковая безопасность в QLua - документация и реальность</a></b> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			<a class="blog-p-user-name" id="bp_e1SfUt1W" href="/user/9815/" bx-tooltip-user-id="9815">kroki</a>, <br />Из поста совершенно не понятно чего Вы от нас хотите.<br />Вы делаете какие-то выводы, ради бога, это Ваше право.<br />Вы спрашиваете зачем нужна функция, Вам был дан ответ и если не хотите ее использовать, Ваше право.<br />В свое время мы сделали функции по запросу пользователей, для их конкретных задач.<br />Ровно как сделали темную тему в терминале по просьбе пользователей, не хотите использовать темную тему никто не заставляет.<br />Да LUA не наш продукт, мы только встроили уже готовое в терминал и мы не можем знать всех нюансов которые в него заложили его авторы, а только то что есть в открытых источниках, ровно также как и Вы.<br />Если есть конкретные вопросы готовы ответить, пока их в Вашем посте не видно, а только какие-то рассуждения и умозаключения. <br />
			<i>15.12.2017 07:18:43, Sergey Gorokhov.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message28228/topic3270/</link>
			<guid>http://forum.quik.ru/messages/forum10/message28228/topic3270/</guid>
			<pubDate>Fri, 15 Dec 2017 07:18:43 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Потоковая безопасность в QLua - документация и реальность</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message28224/topic3270/">Потоковая безопасность в QLua - документация и реальность</a></b> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			Все, кажется я смог перевести слова Михаила: в основном потоке вы вызываете<br />
====code====
<pre>lua_State *L = lua_newstate(...);
lua_State *T = lua_newthread(L);</pre>
=============
<br /><B>L</B> и <B>T</B> разделяют глобальные объекты, и доступ к этим объектам вы лочите. &nbsp;Дальше в основном потоке используете <B>L</B>, а в потоке <B>main()</B> используете <B>T</B>. &nbsp;Да, пишут, что такой вариант вполне рабочий. &nbsp;Ну и, видимо, как-то сериализуете запуск <B>GC</B>, чтобы не работал параллельно с другим потоком и не лез в его данные. &nbsp;Если не трудно, то все же скажите, как, и как именно &quot;блокируются&quot; потоки в <B>table.sconcat()</B> - это все хочется знать, чтобы понимать, как именно лучше писать Lua код, какая операция сколько стоит... &nbsp;Теперь, например, стало ясно, что в начале скрипта нужно писать<br />
====code====
<pre>local string, table, pairs, ipairs = string, table, pairs, ipairs</pre>
=============
и т.д., чтобы не лочить <B>global environment</B> при каждом доступе к <B>string.something()</B> и т.д. <br />
			<i>14.12.2017 20:59:58, kroki.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message28224/topic3270/</link>
			<guid>http://forum.quik.ru/messages/forum10/message28224/topic3270/</guid>
			<pubDate>Thu, 14 Dec 2017 20:59:58 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Потоковая безопасность в QLua - документация и реальность</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message28222/topic3270/">Потоковая безопасность в QLua - документация и реальность</a></b> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			<br />====quote====<br /><a class="blog-p-user-name" id="bp_gjBykpQy" href="/user/17/" bx-tooltip-user-id="17">Sergey Gorokhov</a> написал:<br /><br />====quote====<br /> kroki &nbsp; написал:<br />По-моему в ваших словах противоречие:<br />=============<br />По моему это Ваш код противоречит Вашим словам.<br />Еще раз, согласно Вашему коду никакого одновременного присвоения нет. А значит вопрос совершенно никак не связан с цитатой из документации.<br /><br />=============<br />В документации не идет речи о присвоении, есть выражение "одновременная работа". &nbsp;То есть не только запись, но и чтение. &nbsp;Потоки не могут не читать <B>global environment</B>: всякий раз, когда вы пишите <B>table.something()</B> или <B>string.something()</B>, вы читаете значения <B>_G&#91;"table"&#93;</B> и <B>_G&#91;"string"&#93;</B>. &nbsp;Давайте еще раз:<br /><ol><li>Является ли присвоение переменной значения <B>nil </B>операцией изменения таблицы, в которой переменная хранится? - <B>Да</B>, в Lua присвоение <B>_G&#91;"var"&#93; = nil </B>это операция <B>удаления из таблицы</B>.<br /><li>Обращаются ли разные потоки к таблице глобальных переменных? - <B>Да</B>, как сказано выше, этого не избежать.<br /><li>Можно ли одновременно менять таблицу из одного потока и читать из другого без блокировок? - <B>Нет</B>, согласно документации (и здравому смыслу) нужно использовать потокобезопасные функции.<br /><li>Используются ли потокобезопасные функции при обращении к глобальным переменным? - <B>Нет</B>, к глобальным переменным обращаются напрямую.<br /></ol>Отсюда вывод: присваивать глобальным переменным значение <B>nil</B> из потока нельзя. &nbsp;Не знаю, почему сей логический вывод дается с таким трудом.<br /><br /><br />====quote====<br /><br />====quote====<br /> kroki &nbsp; написал:<br />Попробую угадать:<br /><br />=============<br />Не надо искать скрытый смысл там где его просто нет. <br />Фраза "блокирует выполнение кода в другом потоке" означает ровно то что означает без скрытого смысла.<br />И тут нет никакого сокрального знания.<br /><br />=============<br />Возможно играет роль разница в кругозорах. &nbsp;Вы видите ровно один вариант интерпретации и для вас все однозначно. &nbsp;Я вижу несколько вариантов, начиная с того наблюдения, что словом "блокировка" на русский язык переводят английские термины как <B>blocking</B>, так и <B>locking</B> (и это совершенно разные концепции), и заканчивая семантикой русского языка: если вас спрашивают, "вы курите?", то это может означать как "прямо сейчас", так и "вообще по жизни". &nbsp;Поэтому "блокирует выполнение кода в другом потоке" может означать как захват какой-то блокироки (<B>L</B>ock), так и блокирование (остановку) в каком-то месте кода (<B>B</B>locking); как "прямо сейчас", так и "в момент, когда выполнение потока дойдет до критической секции". &nbsp; Как видите, интерпретаций несколько, и мне хотелось понять, что именно имеется ввиду. &nbsp;Я понял, что вы сделали все, что могли, и ответа не дадите (а я и не утверждаю, что обязаны - вы уже дали достаточно других ответов).<br /><br /><br />====quote====<br /><br />====quote====<br /> kroki &nbsp; написал:<br />Вопрос 3: какой смысл в потокобезопасной сортировке, если ее результат (то есть упорядоченный массив) увидеть (то есть получить к нему доступ) никак нельзя? &nbsp;Если увидеть можно, то, пожалуйста, приведите пример кода. &nbsp;Я утверждаю, что после выхода из table.ssort() и перед любым другим действием другой поток может что-то вставить в массив с помощью table.sinsert(), и, таким образом, нарушить его упорядоченность - а тогда зачем было вообще упорядочивать?<br /><br />=============<br />Цель функции ssort выполнить сортировку таблицы не боясь что во время сортировки в таблице изменятся данные.<br />Ровно это функция и делает. Если не видите смысла использовать эту функцию то просто не используйте и все.<br />Никто не заставляет.<br /><br />=============<br />- Доктор, когда я вот так делаю, у меня болит.<br />- А вы так не делайте.<br /><br /><br />====quote====<br />Если нужно заблокировать остальные потоки во время вывода таблицы, то при чем тут функция ssort?<br /><br />=============<br />Речь была не о выводе конкретно, а о любом доступе к "упорядоченной" таблице. &nbsp;Документация утверждает, что функция упорядочивает, но проверить и воспользоваться этим никак нельзя: если другие потоки не блокировать, то после завершения <B>table.ssort()</B> перед любой другой операцией упорядоченность может быть нарушена. &nbsp;Если же другие потоки блокировать, но зачем вообще "потокобезопасная сортировка" (не говоря о том, что блокировать в QLua API просто нечем)? &nbsp;Опять же, я прямо теряюсь в догадках, почему сей очевидный факт не находит у вас понимания.<br /><br /><br />====quote====<br /><br />====quote====<br /> kroki &nbsp; написал:<br />Если GC запускаются в каждом потоке свой, то как они не "наступают друг другу на пятки", и не конфликтуют с выполнением другого потока?<br />=============<br />В этом вопросе лучше и правильней обратиться к истокам. garbage collector не является нашей разработкой.<br /><br />====quote====<br /> kroki &nbsp; написал:<br />Вопрос 6: как исключается ситуация коллизии между GC в разных потоках, запущенными одновременно? &nbsp;Не могут два разных GC одновременно начать удалять один и тот же объект?<br />=============<br />В нашем ПО, это никак не исключается. Все работает так как это реализовали авторы Lua.<br />Можете проверить поведение функции поставив ряд экспериментов.<br /><br />=============<br />Ага, моменты истины! &nbsp;Если ваши утверждения верны (а я надеюсь, что <B>нет</B>), то вся реализация QLua - абсолютно небезопасна относительно потоков. &nbsp;С ваших слов, вы взяли реализацию Lua, которая к многопоточности абсолютно не готова (там есть объект <B>lua_thread</B>, но это <B>coroutines</B> - совершенно другой зверь), и запустили в разных потоках <B>два</B> интерпретатора на <B>одном environment</B> (то есть используя один объект <B>lua_State</B> - ммм, значит <B>GC</B> все же один) - безо всякой синхронизации. &nbsp;Гляньте второй пост <noindex><a href="http://lua.2524044.n2.nabble.com/Running-multiple-threads-in-a-lua-state-td7658218.html" target="_blank" rel="nofollow">здесь</a></noindex> - пишет как раз автор Lua, и говорит как раз то, что даже если <B>environments</B> разные, шарить один <B>lua_State</B> между потоками нельзя...<br /><br />Ммм, последняя реплика Михаила содержит какой-то намек, но из поста автора Lua следует, что лочить только доступ к глобальным переменным - не достаточно, а если лочить все, что необходимо лочить, то это "makes all Lua code serialized and with a heavy lock/unlock overhead".<br /><br />В общем я понял, что дело мутное. &nbsp;Но спасибо, Сергей! <br />
			<i>14.12.2017 19:52:04, kroki.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message28222/topic3270/</link>
			<guid>http://forum.quik.ru/messages/forum10/message28222/topic3270/</guid>
			<pubDate>Thu, 14 Dec 2017 19:52:04 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Потоковая безопасность в QLua - документация и реальность</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message28201/topic3270/">Потоковая безопасность в QLua - документация и реальность</a></b> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			Добрый день.<br /><br />====quote====<br /><br />1: &nbsp;приводит ли присвоение &nbsp;nil &nbsp;глобальным переменным из функции &nbsp;main() &nbsp;(то есть не главного потока) к неопределенным ситуациям?<br /><br />=============<br /><br />Смотря как написан код<br /><br />
====code====
<pre>
t={}
...
function main()
 ...
 t=nil
 ...
end

OnSmth()
 t.x = 1
 t.y = 2
 t.z = 3 -- тут может возникнуть ошибка attempt to index global 't' (a nil value)
</pre>
=============
<br /><br /><br /><br /><br />====quote====<br /><br />2: &nbsp;имеется ввиду, что другие потоки блокируются при попытке вызвать (ту же или какую-то другую) потокобезопасную функцию (классическая &nbsp;critical section )? &nbsp;Или же вообще все потоки волшебным образом останавливаются, ну, так, &quot;на всякий случай&quot;? :)<br /><br />=============<br />Другой &quot;поток&quot; волшебным образом останавливается, если будет обращение к глобальным данным.<br /><br /><br />====quote====<br /><br />3: &nbsp;как вообще тогда использовать &nbsp;table.ssort() ?<br /><br />=============<br />в описанной Вами ситуации - никак.<br /><br /><br />====quote====<br /><br />Думаем про table.sinsert() и table.sremove():<br />4: в примере выше, что произойдет, если один поток изменит таблицу потокобезопасной функцией как раз в то время, когда другой поток находится где-то в дебрях интерпретатора Lua (внутри ipairs(), t[key], или еще где)? Что именно сделано, чтобы все не &quot;взорвалось&quot;? Или &quot;так делать нельзя&quot;? <br /><br />=============<br />Как и в любых других языках программирования - изменение содержимого контейнера в одном потоке и итерация по элементам в другом может привести к неопределенной ситуации. Данные останутся консистентны, но итераторы (pairs, ipairs) могут работать не так как Вы ожидаете.<br /><br /><br />====quote====<br /><br />5: &nbsp;а какие &quot;сообщения&quot; можно посылать таким образом? &nbsp;Абсолютно любые &quot;типы&quot; Lua, или есть ограничения? &nbsp;Этот вопрос связан со следующим:<br /><br />=============<br />Не совсем понятно, поясните.<br /><br /><br />====quote====<br /><br />6: &nbsp;а как потоки дружат со сборщиком мусора ( garbage collector )? &nbsp;Он один на все потоки, или по одному на каждый? &nbsp;Если один, то в каком потоке выполняется, и что именно сделано, чтобы &nbsp;GC &nbsp;в одном потоке не &quot;взорвал&quot; другой работающий поток, и не &quot;взорвался&quot; сам, считая свободной память, которую другой поток как раз начинает использовать)? &nbsp;Если же &nbsp;GC &nbsp;у каждого потока свой, то в случае &nbsp;message passing &nbsp;как в примере выше как именно передается &nbsp;ownership &nbsp;(то есть чей &nbsp;GC &nbsp;отвечает за рекламацию сообщения)?<br /><br />=============<br />Сборщик мусора один. Вообще потоки не являются потоками в &quot;классическом&quot; понимании. Это скорее новый объект с отдельным стеком для вызовов функций и локальных переменных. При этом у них общие глобальные данные. Попытка обращения к ним из одного &quot;потока&quot; блокирует другой, если он тоже обращается к ним. <br />
			<i>14.12.2017 10:31:59, Michael Bulychev.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message28201/topic3270/</link>
			<guid>http://forum.quik.ru/messages/forum10/message28201/topic3270/</guid>
			<pubDate>Thu, 14 Dec 2017 10:31:59 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Потоковая безопасность в QLua - документация и реальность</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message28199/topic3270/">Потоковая безопасность в QLua - документация и реальность</a></b> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			<br />====quote====<br /><a class="blog-p-user-name" id="bp_U4Wr5rhE" href="/user/9815/" bx-tooltip-user-id="9815">kroki</a> написал:<br />По-моему в ваших словах противоречие:<br />=============<br />По моему это Ваш код противоречит Вашим словам.<br />Еще раз, согласно Вашему коду никакого одновременного присвоения нет. А значит вопрос совершенно никак не связан с цитатой из документации.<br />Либо Ваш пример кода не соответствует вопросу, либо вопрос поставлен некорректно<br /><br /><br />====quote====<br /><a class="blog-p-user-name" id="bp_KV70AMMF" href="/user/9815/" bx-tooltip-user-id="9815">kroki</a> написал:<br />Попробую угадать:<br /><br />=============<br />Не надо искать скрытый смысл там где его просто нет. <br />Фраза "блокирует выполнение кода в другом потоке" означает ровно то что означает без скрытого смысла.<br />И тут нет никакого сокрального знания.<br /><br /><br />====quote====<br /><a class="blog-p-user-name" id="bp_NrZX37KD" href="/user/9815/" bx-tooltip-user-id="9815">kroki</a> написал:<br />Вопрос 3: какой смысл в потокобезопасной сортировке, если ее результат (то есть упорядоченный массив) увидеть (то есть получить к нему доступ) никак нельзя? &nbsp;Если увидеть можно, то, пожалуйста, приведите пример кода. &nbsp;Я утверждаю, что после выхода из table.ssort() и перед любым другим действием другой поток может что-то вставить в массив с помощью table.sinsert(), и, таким образом, нарушить его упорядоченность - а тогда зачем было вообще упорядочивать?<br /><br />=============<br />Цель функции ssort выполнить сортировку таблицы не боясь что во время сортировки в таблице изменятся данные.<br />Ровно это функция и делает. Если не видите смысла использовать эту функцию то просто не используйте и все.<br />Никто не заставляет.<br />Если нужно заблокировать остальные потоки во время вывода таблицы, то при чем тут функция ssort?<br /><br />====quote====<br /><a class="blog-p-user-name" id="bp_PplbDcbX" href="/user/9815/" bx-tooltip-user-id="9815">kroki</a> написал:<br />Если GC запускаются в каждом потоке свой, то как они не "наступают друг другу на пятки", и не конфликтуют с выполнением другого потока?<br />=============<br />В этом вопросе лучше и правильней обратиться к истокам. garbage collector не является нашей разработкой.<br /><br /><br />====quote====<br /><a class="blog-p-user-name" id="bp_R6M0rlsq" href="/user/9815/" bx-tooltip-user-id="9815">kroki</a> написал:<br />Вопрос 6: как исключается ситуация коллизии между GC в разных потоках, запущенными одновременно? &nbsp;Не могут два разных GC одновременно начать удалять один и тот же объект?<br />=============<br />В нашем ПО, это никак не исключается. Все работает так как это реализовали авторы Lua.<br />Можете проверить поведение функции поставив ряд экспериментов. <br />
			<i>14.12.2017 10:08:00, Sergey Gorokhov.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message28199/topic3270/</link>
			<guid>http://forum.quik.ru/messages/forum10/message28199/topic3270/</guid>
			<pubDate>Thu, 14 Dec 2017 10:08:00 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Потоковая безопасность в QLua - документация и реальность</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message28191/topic3270/">Потоковая безопасность в QLua - документация и реальность</a></b> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			<br />====quote====<br /><a class="blog-p-user-name" id="bp_T4pGLx4M" href="/user/17/" bx-tooltip-user-id="17">Sergey Gorokhov</a> написал:<br /><br />====quote====<br /> kroki &nbsp; написал:<br />Вопрос 1: приводит ли присвоение nil глобальным переменным из функции main() (то есть не главного потока) к неопределенным ситуациям?<br /><br />=============<br />А как связано простое присвоение nil с одновременной работой из функций обратного вызова скрипта и функции main()?<br /><br />=============<br />В момент одного из таких присваиваний (то есть удалений) реализация Lua может решить аллоцировать для таблицы меньший кусок памяти, перехэшировать, и пр. &nbsp;Если во время такого передела другой поток обратится к какой-то глобальной переменной, то...<br /><br />====quote====<br />Вы обыгрываете совершенно разные сценарии, при этом считаете что это одно и тоже.<br />Вот если бы Вы из разных потоков одновременно присваивали nil, тогда да, согласно документации это может привести к неопределенным последствиям.<br /><br />=============<br />По-моему в ваших словах противоречие: вы же не можете знать, делаете ли вы &quot;простое присваивание nil&quot; (которое по-вашему не связано с функцией main()), или &quot;из разных потоков одновременно присваивали nil&quot;, которое делать нельзя - вдруг присваивание делается изнутри какой-то функции, которую даже не вы написали. &nbsp;Отсюда:<br /><br /><B>Ответ 1:</B> присваивать глобальным переменным <B>nil</B> нельзя. &nbsp;Динамически создавать новые глобальные имена также нельзя. &nbsp;Так?<br /><br /><br />====quote====<br /><br />====quote====<br /> kroki &nbsp; написал:<br />Читаем документацию дальше: Выполнение потокобезопасной функции блокирует выполнение кода в другом потоке до окончания работы функции.<br /><br />=============<br />на наш взгляд фраза &quot;блокирует выполнение кода в другом потоке&quot; вполне понятна и не требует уточнений.<br /><br />=============<br />И не делиться сакральным знанием - ваша политика? :) &nbsp;Но я понял: другой поток останавливается, даже если он не пытается вызвать потокобезопасную функцию. &nbsp;Попробую угадать:<br /><br /><B>Ответ 2:</B> в интерпретатор Lua (видимо, перед выполнением следующей инструкции байт-кода) встроена проверка флага, что другой поток вызывает потокобезопасную функцию. &nbsp;Увидев флаг, интерпретатор останавливается и ждет, пока другой поток выйдет из функции. &nbsp;Конечно, можtт получиться так, что поток уже выполняет код <B>GC</B>, который написан на <B>C</B> и в Lua долго не вернется, флага не увидит. &nbsp;Но это превращает <B>вопрос 2</B> в <B>вопрос 6</B>, так что этот вопрос снимаю.<br /><br /><br />====quote====<br /><br />====quote====<br /> kroki &nbsp; написал:<br />Как только table.ssort() закончит работу другой поток может добавить новые данные - и у нас опять потенциально не упорядоченная таблица, которую мы и напечатаем.<br />Вопрос 3: как вообще тогда использовать table.ssort()?<br /><br />=============<br />А чего Вы ожидали? что оно само будет где-то параллельно сортироваться после окончания ssort? Нет такого не будет.<br /><br />=============<br />Не уверен, поняли ли вы вопрос (я ожидал только его понимания, больше ничего). &nbsp;Перефразирую: <br /><br /><B>Вопрос 3:</B> какой смысл в потокобезопасной сортировке, если ее результат (то есть упорядоченный массив) увидеть (то есть получить к нему доступ) никак нельзя? &nbsp;Если увидеть можно, то, пожалуйста, приведите пример кода. &nbsp;Я утверждаю, что после выхода из table.ssort() и перед любым другим действием другой поток может что-то вставить в массив с помощью table.sinsert(), и, таким образом, нарушить его упорядоченность - а тогда зачем было вообще упорядочивать?<br /><br /><br />====quote====<br /><br />====quote====<br /> kroki &nbsp; написал:<br />Вопрос 4: в примере выше, что произойдет, если один поток изменит таблицу потокобезопасной функцией как раз в то время, когда другой поток находится где-то в дебрях интерпретатора Lua (внутри ipairs(), t&#91;key&#93;, или еще где)? &nbsp;Что именно сделано, чтобы все не &quot;взорвалось&quot;? &nbsp;Или &quot;так делать нельзя&quot;?<br /><br />=============<br />Вы же сами выше процетировали:<br /><br />====quote====<br /> kroki &nbsp; написал:<br />Выполнение потокобезопасной функции &nbsp;блокирует выполнение кода в другом потоке &nbsp;до окончания работы функции.<br />=============<br /><br />=============<br />И там же я сказал, что смысл фразы мне не вполне ясен. &nbsp;Если <B>ответ 2</B> я понял правильно, то да, <B>вопрос 4</B> снимается.<br /><br /><br />====quote====<br /><br />====quote====<br /> kroki &nbsp; написал:<br />Вопрос 5: а какие &quot;сообщения&quot; можно посылать таким образом? &nbsp;Абсолютно любые &quot;типы&quot; Lua, или есть ограничения? &nbsp;Этот вопрос связан со следующим:<br /><br />=============<br />Если вопрос в том, что можно вставить в таблицу, то это совсем никак не связано с вопросом из п.6.<br /><br />=============<br />И, следовательно, вопрос не в том, что можно вставить в таблицу ;). &nbsp;Подробнее ниже.<br /><br /><br />====quote====<br /><br />====quote====<br /> kroki &nbsp; написал:<br />Вопрос 6: а как потоки дружат со сборщиком мусора (garbage collector)? &nbsp;Он один на все потоки, или по одному на каждый? &nbsp;Если один, то в каком потоке выполняется, и что именно сделано, чтобы GC в одном потоке не &quot;взорвал&quot; другой работающий поток, и не &quot;взорвался&quot; сам, считая свободной память, которую другой поток как раз начинает использовать)? &nbsp;Если же GC у каждого потока свой, то в случае message passing как в примере выше как именно передается ownership (то есть чей GC отвечает за рекламацию сообщения)?<br /><br />=============<br />Все LUA функции выполняются в том потоке в котором вызваны и не важно garbage collector это или любая другая функция.<br />Потокобезопасные функции отличаются только тем что блокируют другой поток пока сами выполняются и опять же в том потоке где запущены. И garbage collector к ним не относится.<br />=============<br />Раз из разных потоков можно обращаться к одним и тем же глобальным именам, значит разные потоки работают с одним и тем же <B>global environment </B>(точнее, могла быть и копия, но нет, проверял)<B>. &nbsp;</B>Если <B>GC</B><B> </B>запускаются в каждом потоке свой, то как они не &quot;наступают друг другу на пятки&quot;, и не конфликтуют с выполнением другого потока? &nbsp;Например, в одном потоке запустился <B>GC</B>, но работает-то он со всей памятью (раз <B>environment </B>общий). &nbsp;Если никакой синхронизции между потоками нет, то события &quot;объект больше не используется&quot; и &quot;на объект больше никто не ссылается&quot; в общем случае разные потоки могут обозревать в разном порядке, как из-за <B>out of order execution</B>, так и в банальных случаях, когда два <B>GC </B>в разных потоках одновременно увидят, что такая-то таблица более не используется, и одновременно попытаются ее освободить - возможно возникнет бо-бо :). &nbsp;<B>Вопрос 5</B> вырос из предположения, что разные <B>GC</B> работают каждый на своих данных, которыми он &quot;владеет&quot;, и коллизий не бывает. &nbsp;Я более не думаю, что это так (снимаю <B>вопрос 5</B>), но тогда остается:<br /><br /><B>Вопрос 6:</B> как исключается ситуация коллизии между <B>GC</B> в разных потоках, запущенными одновременно? &nbsp;Не могут два разных <B>GC</B> одновременно начать удалять один и тот же объект? <br />
			<i>14.12.2017 09:13:52, kroki.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message28191/topic3270/</link>
			<guid>http://forum.quik.ru/messages/forum10/message28191/topic3270/</guid>
			<pubDate>Thu, 14 Dec 2017 09:13:52 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Потоковая безопасность в QLua - документация и реальность</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message28187/topic3270/">Потоковая безопасность в QLua - документация и реальность</a></b> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			<br />====quote====<br /><a class="blog-p-user-name" id="bp_2SI0uJdf" href="/user/9815/" bx-tooltip-user-id="9815">kroki</a> написал:<br />Вопрос 1: приводит ли присвоение nil глобальным переменным из функции main() (то есть не главного потока) к неопределенным ситуациям?<br /><br />=============<br />А как связано простое присвоение nil с одновременной работой из функций обратного вызова скрипта и функции main()?<br />Вы обыгрываете совершенно разные сценарии, при этом считаете что это одно и тоже.<br />Вот если бы Вы из разных потоков одновременно присваивали nil, тогда да, согласно документации это может привести к неопределенным последствиям.<br />Для избежания такой неопределенности, придуманы функции из главы руководства "Потокобезопасные функции для работы с таблицами Lua"<br /><br /><br />====quote====<br /><a class="blog-p-user-name" id="bp_WUybh66S" href="/user/9815/" bx-tooltip-user-id="9815">kroki</a> написал:<br />Читаем документацию дальше:ЦитатаВыполнение потокобезопасной функции блокирует выполнение кода в другом потоке до окончания работы функции.<br />Вопрос 2: имеется ввиду, что другие потоки блокируются при попытке вызвать (ту же или какую-то другую) потокобезопасную функцию (классическая critical section)? &nbsp;Или же вообще все потоки волшебным образом останавливаются, ну, так, "на всякий случай"? :)<br /><br />=============<br />на наш взгляд фраза "блокирует выполнение кода в другом потоке" вполне понятна и не требует уточнений.<br /><br /><br />====quote====<br /><a class="blog-p-user-name" id="bp_X3gzxCPy" href="/user/9815/" bx-tooltip-user-id="9815">kroki</a> написал:<br />Как только table.ssort() закончит работу другой поток может добавить новые данные - и у нас опять потенциально не упорядоченная таблица, которую мы и напечатаем.<br />Вопрос 3: как вообще тогда использовать table.ssort()?<br /><br />=============<br /><br />А чего Вы ожидали? что оно само будет где-то параллельно сортироваться после окончания ssort? Нет такого не будет.<br /><br />====quote====<br /><a class="blog-p-user-name" id="bp_7CRlvn6j" href="/user/9815/" bx-tooltip-user-id="9815">kroki</a> написал:<br />Вопрос 4: в примере выше, что произойдет, если один поток изменит таблицу потокобезопасной функцией как раз в то время, когда другой поток находится где-то в дебрях интерпретатора Lua (внутри ipairs(), t[key], или еще где)?  Что именно сделано, чтобы все не "взорвалось"?  Или "так делать нельзя"?<br /><br />=============<br />Вы же сами выше процетировали:<br /><br />====quote====<br /><a class="blog-p-user-name" id="bp_fJ3cDNwm" href="/user/9815/" bx-tooltip-user-id="9815">kroki</a> написал:<br />Выполнение потокобезопасной функции <B>блокирует выполнение кода в другом потоке</B> до окончания работы функции.<br />=============<br /><br /><br />====quote====<br /><a class="blog-p-user-name" id="bp_ix3Rjnnf" href="/user/9815/" bx-tooltip-user-id="9815">kroki</a> написал:<br />Вопрос 5: а какие "сообщения" можно посылать таким образом? &nbsp;Абсолютно любые "типы" Lua, или есть ограничения? &nbsp;Этот вопрос связан со следующим:<br /><br />=============<br />Если вопрос в том, что можно вставить в таблицу, то это совсем никак не связано с вопросом из п.6.<br /><br /><br />====quote====<br /><a class="blog-p-user-name" id="bp_4HHyfYVK" href="/user/9815/" bx-tooltip-user-id="9815">kroki</a> написал:<br />Вопрос 6: а как потоки дружат со сборщиком мусора (garbage collector)? &nbsp;Он один на все потоки, или по одному на каждый? &nbsp;Если один, то в каком потоке выполняется, и что именно сделано, чтобы GC в одном потоке не "взорвал" другой работающий поток, и не "взорвался" сам, считая свободной память, которую другой поток как раз начинает использовать)? &nbsp;Если же GC у каждого потока свой, то в случае message passing как в примере выше как именно передается ownership (то есть чей GC отвечает за рекламацию сообщения)?<br /><br />=============<br />Все LUA функции выполняются в том потоке в котором вызваны и не важно garbage collector это или любая другая функция.<br />Потокобезопасные функции отличаются только тем что блокируют другой поток пока сами выполняются и опять же в том потоке где запущены. И garbage collector к ним не относится. <br />
			<i>14.12.2017 05:49:48, Sergey Gorokhov.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message28187/topic3270/</link>
			<guid>http://forum.quik.ru/messages/forum10/message28187/topic3270/</guid>
			<pubDate>Thu, 14 Dec 2017 05:49:48 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Потоковая безопасность в QLua - документация и реальность</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message28186/topic3270/">Потоковая безопасность в QLua - документация и реальность</a></b> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			Ниже несколько вопросов к поддержке и/или знатокам по теме потоковой безопасности.<br /><br />Читаем документацию:<br />====quote====<br />Одновременная работа с таблицами из функций обратного вызова скрипта и функции main() может приводить к неопределенным ситуациям. <br /><br />=============<br />В языке Lua все переменные на самом деле являются ключами таблиц, называемых <B>environment</B>s. &nbsp;Присвоение ключу значения <B>nil</B> удаляет его из таблицы. &nbsp;То есть, если в коде написано
====code====
<pre>var = 5&nbsp;&nbsp;-- глобальная переменная

function main()
&nbsp;&nbsp; var = nil
end 
</pre>
=============
то это то же самое, что и
====code====
<pre>_G&#91;"var"&#93; = 5&nbsp;&nbsp;-- глобальная переменная

function main()
&nbsp;&nbsp; _G&#91;"var"&#93; = nil
end 
</pre>
=============
(в новых версиях Lua вместо <B>_G </B>теперь <B>_ENV</B>, но не суть). &nbsp;Видно, что функция <B>main()</B> удаляет ключ <B>var</B> из таблицы <B>_G</B>.<br /><B>Вопрос 1:</B> приводит ли присвоение <B>nil</B> глобальным переменным из функции <B>main()</B> (то есть не главного потока) к неопределенным ситуациям?<br /><br />Читаем документацию дальше:<br />====quote====<br />Выполнение потокобезопасной функции блокирует выполнение кода в другом потоке до окончания работы функции.<br /><br />=============<br /><B>Вопрос 2: </B>имеется ввиду, что другие потоки блокируются при попытке вызвать (ту же или какую-то другую) потокобезопасную функцию (классическая <B>critical section</B>)? &nbsp;Или же вообще все потоки волшебным образом останавливаются, ну, так, &quot;на всякий случай&quot;? :)<br /><br />Еще читаем:<br />====quote====<br />В таблице представлены стандартные функции Lua и соответствующие им потокобезопасные аналоги: <br />concat &nbsp; sconcat <br />remove &nbsp;sremove <br />insert &nbsp; &nbsp; sinsert <br />sort &nbsp; &nbsp; &nbsp; ssort <br /><br />=============<br />Про <B>table.sconcat() </B>вопросов нет (ну хоть что-то понял! :)). &nbsp;Думаем про <B>table.ssort():
====code====
<pre>local t = {}

function OnSomething(param)&nbsp;&nbsp;-- какой-то callback
&nbsp;&nbsp; table.sinsert(t, param)
end

function main()
&nbsp;&nbsp; table.ssort(t)
&nbsp;&nbsp; for _, v in ipairs(t) do
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(v)
&nbsp;&nbsp; end
end
</pre>
=============
</B>Как только <B>table.ssort() </B>закончит работу другой поток может добавить новые данные - и у нас опять потенциально не упорядоченная таблица, которую мы и напечатаем.<br /><B>Вопрос 3: </B>как вообще тогда использовать <B>table.ssort()</B>?<br /><br />Думаем про <B>table.sinsert()</B> и <B>table.sremove()</B>:<br /><B>Вопрос 4: </B>в примере выше, что произойдет, если один поток изменит таблицу потокобезопасной функцией как раз в то время, когда другой поток находится где-то в дебрях интерпретатора Lua (внутри <B>ipairs()</B>,<B> t&#91;key&#93;</B>, или еще где)? &nbsp;Что именно сделано, чтобы все не &quot;взорвалось&quot;? &nbsp;Или &quot;так делать нельзя&quot;?<br /><br />Но предположим, что мы используем<I>только </I>потокобезопасные функции и другими способами к таблице не обращаемся, и реализуем классический <B>message passing</B>, то есть очередь сообщений между потоками:
====code====
<pre>local mqueue = {}

function OnSomething(param)&nbsp;&nbsp;-- какой-то callback
&nbsp;&nbsp; while true do
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local msg = table.sremove(mqueue, 1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if not msg then break end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-- обрабатываем сообщение msg (например, меняем логику работы этого callback)
&nbsp;&nbsp; end
&nbsp;&nbsp; -- обрабатываем param согласно (возможно новой) логике
end

function main()
&nbsp;&nbsp; ...
&nbsp;&nbsp; table.sinsert(&#60;сообщение&#62;)
&nbsp;&nbsp; ...
end
</pre>
=============
<B>Вопрос 5: </B>а какие &quot;сообщения&quot; можно посылать таким образом? &nbsp;Абсолютно любые &quot;типы&quot; Lua, или есть ограничения? &nbsp;Этот вопрос связан со следующим:<br /><br /><B>Вопрос 6: </B>а как потоки дружат со сборщиком мусора (<B>garbage collector</B>)? &nbsp;Он один на все потоки, или по одному на каждый? &nbsp;Если один, то в каком потоке выполняется, и что именно сделано, чтобы <B>GC</B> в одном потоке не &quot;взорвал&quot; другой работающий поток, и не &quot;взорвался&quot; сам, считая свободной память, которую другой поток как раз начинает использовать)? &nbsp;Если же <B>GC</B> у каждого потока свой, то в случае <B>message passing</B> как в примере выше как именно передается <B>ownership</B> (то есть чей <B>GC</B> отвечает за рекламацию сообщения)?<br /><br />Очень надеюсь получить ответы на все вопросы (и в особенности на 6-й) - хочется проникнуться доверием к реализации, управляющей моими активами. :)<br /><br />Заранее спасибо! <br />
			<i>14.12.2017 01:22:58, kroki.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message28186/topic3270/</link>
			<guid>http://forum.quik.ru/messages/forum10/message28186/topic3270/</guid>
			<pubDate>Thu, 14 Dec 2017 01:22:58 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
	</channel>
</rss>
