Size: a a a

2019 September 27

S

Snusmumriken in pro.lua
Александр Караев
Привет всем.
Допустим, существует некий глобальный стейт L. В нем есть какие переменные. Мы заспаунили тред, запустили в нем корутину, в ней создали какой-то объект a = { ... };.
Правильно ли я понимаю, что "владелец" a - это не L, а некий дочерний стейт, стейт потока?
Что произойдет с владельцем, если я запишу ссылку на a в глобальные переменные L, после чего поток и корутина умрут? Я получу мертвую ссылку и сегфолт в дальнейшем?
На луёвой стороне, есть только стейт, содержащий области видимости.
Что ты подразумеваешь под "потоками + корутинами"? Если потоки ("многопроцессорные") тут вторичные и не используются (или используются с другим луа-стейтом) то исключи их из вопроса.

Что я понял: у тебя есть луа-стейт в котором запускается куча корутин, использующих какую-то глобальную фигню, но оно дропает когда ты принудительно её сносишь unref'ом.
источник

АК

Александр Караев in pro.lua
Snusmumriken
На луёвой стороне, есть только стейт, содержащий области видимости.
Что ты подразумеваешь под "потоками + корутинами"? Если потоки ("многопроцессорные") тут вторичные и не используются (или используются с другим луа-стейтом) то исключи их из вопроса.

Что я понял: у тебя есть луа-стейт в котором запускается куча корутин, использующих какую-то глобальную фигню, но оно дропает когда ты принудительно её сносишь unref'ом.
Я юзаю sol2 в качестве абстракции, там используются понятия sol::thread и sol::coroutine. Для каждой корутины там нужно создавать тред (lua_newthread используется внутри sol::thread), чтобы одновременно могли существовать разные корутины. И вот у каждого треда там свой lua_State*, который как я понял "дочерний" для основного
источник

АК

Александр Караев in pro.lua
То, что существуют "дочерние" стейты - это факт. Я логгировал их адреса :)
Видимо, они легковесные и как-то наследуют большую часть функционала от основного
источник

S

Snusmumriken in pro.lua
В чистых луях, как бы ты не изгалялся, ты не можешь вынести "ссылку на переменную из мёртвой корутины" куда либо ещё, если смог — эта ссылка не завязана на корутину, она как бы общая.


S = {}

function coroutined_stuff()
 local t = {blabla}
 S[1] = t
end

coroutine.wrap(coroutined_stuff)()

Переменная t не относится к корутине, она создаётся в "куче" текущего стейса, и в корутине появляется просто ссылка на неё, когда корутина умирает — ничто не мешает ей остаться в S.


Ну вот, ты ещё и используешь sol2, вот тут вот может быть что-то ужасное.
источник

S

Snusmumriken in pro.lua
Александр Караев
То, что существуют "дочерние" стейты - это факт. Я логгировал их адреса :)
Видимо, они легковесные и как-то наследуют большую часть функционала от основного
Есть шанс что это тупое копирование стейта, с каким-то извращенским провешиванием ссылок.
источник

АК

Александр Караев in pro.lua
> Переменная t не относится к корутине, она создаётся в "куче", и в корутине просто ссылка на неё, когда корутина умирает — ничто не мешает ей остаться в S.

Но каждая переменная относится к какому-то конкретному lua_State*, которых, как я выяснил, у меня много. Изначально я пытался запускать корутины на основном стейте без sol::thread, но больше одной одновременно работать не хотели ни в какую. У них был общий контекст/стек, поэтому при запуске второй корутины у меня просто глючила первая.

Могу ошибаться, это наблюдения
источник

АК

Александр Караев in pro.lua
Snusmumriken
Есть шанс что это тупое копирование стейта, с каким-то извращенским провешиванием ссылок.
lua_State *lua_newthread (lua_State *L);
Creates a new thread, pushes it on the stack, and returns a pointer to a lua_State that represents this new thread. The new state returned by this function shares with the original state all global objects (such as tables), but has an independent execution stack.
источник

АК

Александр Караев in pro.lua
> has an independent execution stack.
что мне и требовалось для пула корутин
источник

S

Snusmumriken in pro.lua
Хех, пришло время толкать лекцию на тему многопроцессорности.
источник

S

Snusmumriken in pro.lua
Карочи, есть два основных типа "многопоточки":
— Лёгкие треды (они же "зелёные"), это типа корутин. Хотя у разных ЯП бывают разные реализации, где-то кажется можно даже нарваться на "многопроцессорные" извращения, но не в луа. Их прекол в том, что это фактически другая организация кода. Как будто много-много наставленных goto (плюс свапы стеков и окружения). Их можно наплодить сто тыщ мильярдов, и они очень быстро свапаются, отлично заходит под асинхронный код, и его можно писать так как будто он нормальный и синхронный, правда если что-то заблокирует исполнение — оно будет заблокировано, и всё будет стоять: goto же, почти ничего больше. Луёвые корутины — именно такие.

— Нормальные треды. Это когда язык требует у ОС, мол: "выдай мне тред, и загони в него вот это вот", например виртуальную машину скриптового языка вместе со скриптом. И операционная система уже им занимается: выделяет процессорное время на разных ядрах, помогает размечать память под каждый отдельный поток и так далее. Это полностью отдельный процесс, но если родительский грохнут, то детей через некоторое время вытрет ОС. Их не стоит плодить сто тыщ мильярдов, потому что свапы между потоками ОС проворачивает довольно медленно, плюс они начинают конкурировать за процессорное время и мешают друг другу, как правило, таких потоков (если они сильно нагружены) приложение создаёт не больше N - 1, где N — количество физических ядер цпу. Общение же между такими потоками обычно через пайпы ОС (пересылка строчек), сокеты (пересылка строчек) или шаред-мемори (общие участки памяти, как правило для хранения общих строчек, но иногда там хранят и структуры, вот извращенцы).
источник

АК

Александр Караев in pro.lua
Я понимаю, что корутины не исполняются асинхронно. Мне это и не нужно. Мне просто нужно иметь много корутин одновременно, которые можно паузить и запускать без взаимного ущерба
источник

АК

Александр Караев in pro.lua
И фактически у меня один поток (который системный, настоящий)
источник

S

Snusmumriken in pro.lua
Так вот да, sol::thread видать создаёт отдельный ОС-поток, жди пока он не закончит работу полностью прежде чем что-то unref'ать.
источник

АК

Александр Караев in pro.lua
Не создаёт он отдельный процесс, он вызывает https://pgl.yoyo.org/luai/i/lua_newthread
источник

S

Snusmumriken in pro.lua
А как ты их одновременно запускаешь?
источник

АК

Александр Караев in pro.lua
Под одновременно я подразумеваю, что есть пул и я в цикле последовательно их resume'лю. Завершившиеся удаляю, иногда добавляю новые
источник

АК

Александр Караев in pro.lua
Одновременно существует больше одной запаузенной корутины
источник

S

Snusmumriken in pro.lua
Хмм, тогда они исполняются не одновременно.

Понял.
источник

АК

Александр Караев in pro.lua
Ну да, извиняюсь, если запутал
источник

S

Snusmumriken in pro.lua
Но тогда это ничем не отличается от

local ROUTINES = {}

function addRoutine(f, ...)
 ROUTINES[#ROUTINES + 1] = coroutine.create(f, ...)
end

function updateRoutines()
 for i = #ROUTINES, 1, -1 do
   local r = ROUTINES[i]
   if coroutine.status(r) == 'dead' then
     table.remove(ROUTINES, i)
   else
     coroutine.resume(r)
   end
 end
end

Я начинаю плохо понимать зачем нужны потоки и дочерние стейты.
источник