Здравствуйте, Evgeny.Panasyuk, Вы писали:
V>>Где ты предлагаешь разместить аналог своего asio::coroutine в future<>?
EP>Там же где и обычное обычное замыкание-продолжение. EP>Абстрагируйся от asio::coroutine, представь простое замыкание-продолжение. Например у нас вместо: EP>
EP>future<int> sum()
EP>{
EP> int x = await foo();
EP> int y = await bar();
EP> return x + y;
EP>}
EP>
Оба раза в куче. ))
Т.е. лямбда создаётся на стеке, но при сохранении её в std::function, происходит создание её копии в куче, потому что объект function устроен как-то так (схематично):
Реальное исполнение отличается от приведенного попыткой оптимизации для маленьких замыканий, типа как для обычных адресов ф-ий, чтобы, если std::function создаётся от аргумента-простого адреса ф-ии, ничего в куче не создавать.
EP>И почему stackless корутина должна размещаться в каком-то другом месте?
Потому что, как и в случае std::string, для которого тоже есть некая оптимизация "маленьких" значений, реальный размер корутины заранее предугадать невозможно. Собсно, открой <functional> и посмотри на кол-во вызовов new.
V>>Я бы его разместил в объекте-наследнике того самого shared_state, который, в свою очередь, создаётся на куче.
EP>А здесь можно вообще не менять ни сам future, ни лезть в его внутренности (типа наследования от shared_state). Потому что используем ли мы обычные продолжения, или объект-автомат (ручной или сгенерированный stackless coroutine) — это совершенно ортогонально тому где мы их размещаем.
Если используем future, то у нас в любом случае будет выделение памяти из кучи. Я лишь предлагаю свести кол-во выделений к минимуму, реализовав корутину как наследника future, либо как в случае с make_shared, просто расположив оба объекта в одном куске памяти (что фактически идентично с т.з. использования памяти). И я УВЕРЕН, что это именно так и будет. Даже могу поспорить на денюжку. )) Сорри, но это слишком очевидно, чтобы это "промухать". Не промухают, я уверен.
V>>Т.к. тип iterator<> еще не специфирован, вполне возможно, что у него будет некое зарезервированное поле, в котором можно поместить целочисленную переменную — состояние автомата-корутины.
EP>Ты понимаешь что над корутинами из Boost.Asio можно сделать обёртку-итератор, в котором полностью будет хранится вся корутина? Или показать пример?
Не надо пример. Я, как раз, понимаю о чем речь, но ты не вникаешь в суть моих вопросов. Я всегда спрашиваю одно и то же — какой будет тип результирующего объекта? Можно ли объявить переменную этого типа БЕЗ объявления корутины, а реальную корутину присвоить "потом" — как в твоём сценарии сериализации?
V>>Если твоя легковесная корутина будет содержать в себе другие корутины, то нужно эмулировать стек для их правильного обхода. И тут уже, извини, но без выделения памяти в куче — никак. EP>Зачем?
Для рекурсии. В т.ч. всевозможной неявной, через вызовы, скажем, захваченных в лямбду методов-переменных.
EP>Вложенная корутина будет просто полем объекта внешней корутины
Ты забыл, что корутина у нас stack-less, поэтому стек ей придётся нарисовать ручками. И этот стек — штука динамическая, увы))
Поэтому — в куче.
EP>Вот пример, в нём нет никаких аллокаций в куче
(скипнул пример)
В этом примере нет, ес-но. Потому что нет недетерминированного стека вызовов.
Здравствуйте, Ikemefula, Вы писали:
N>>А что, коллстек стал панацеей? Если у тебя уже мусор в данных, а откуда он появился, неизвестно, все подробности генерации давно забылись — у тебя на руках только мусор с момента его осознания таковым. N>>Я действительно не вижу разницы. Если тебе нужны в рантайме какие-то подробности о происходящем, их можно вложить в контекст (например, через хитроназванные ключи объектов). Но для процедурного те же проблемы. I>Колстек это не панацея, но он очень сильно помогает. Можно например выяснить, откуда пошел мусор. I>"вложить в контекст" — это ты изобретаешь тот самый колстек.
Не-а. Я как раз обобщаю до правильного построения вопроса. Call stack — это очень частный случай истории: только те вызовы, которые ещё не редуцировались. Правильный вопрос — что нужно из истории, в общем смысле. Для примера — многие любят отладчик, как средство работы — расставить breakpoint'ы, пройтись пошагово... как только ты выходишь за пределы показа только того же call stack, ты переходишь к рассмотрению истории в широком смысле (в неё будет входить видимый тебе путь выполнения с переменными по ходу и т.п.)
Так вот — call stack это попсня от истории — это только то, что невозможно не скрыть. (Хотя современные компиляторы с их инлайнингом и прочими мерами способны и тут убрать нужное — я с gcc регулярно наблюдаю даже при -Og, что какое-то вполне нужное значение оказалось optimized out. Erlang, аналогично, при хвостовой рекурсии исключает предыдущие инвокации того же уровня, при этом даже не сохраняя счётчик хвостов. Пока у него в истории не появились номера строк, было иногда крайне сложно понять, откуда же пришли.)
I>В многопоточном коде я бы сказал 70-80% проблем решаются с помощью этого фокуса. Если проблема с забытыми ссылками, здесь, опять же, помогает колстек — в том же профайлере.
Забытые ссылки — ты явно не то имеешь в виду, что я. Я имел в виду в managed среде то, что не очищается через GC, потому что где-то в сложных данных осталась на него ссылка.
I>>>Не получится чесно остановить тот же http.get. И здесь другой фокус- как только отпускаешь отладчик, получаешь автоматом вырожденный кейс, когда респонсы валятся лавиной. N>>А что, с остановкой всех тредов ты его не получаешь? I>Полчаешь, только ручной работы несравнимо меньше"
Здравствуйте, netch80, Вы писали:
N>>>Если бы это было серьёзной проблемой, давно бы в винде встроили SCTP из коробки. V>>Причем тут SCTP? N>Message-oriented с гарантией доставки, всё, как ты просил.
А разве по нему можно пулять произвольные сообщения?
=======
Ну и дело-то не в винде, ес-но. Весь интернет построен на юникс-совеместимых системах. Винда больше на клиенте.
Ну и проблему установления и разрыва TCP-соединения тоже ведь не я придумал. Т.е. вот этот ненужный пинг-понг, он же не только при установлении TCP-соединения происходит? Помнишь же ту оптимизацию, когда рекомендуется для сокращения пинг-понгов рвать соединение не клиентом, а сервером? ))
Но в реальности соединение чаще рвет клиент-браузер, гоняя по сети уйму ненужных пакетов.
Это реальная дичь, о которой уже лет 10 регулярно говорится, но вот имеем что имеем. Легаси, мать его так.
Здравствуйте, vdimas, Вы писали:
V>>Вдогонку. Что насчет локальных переменных корутины? Где их хранить? EP>Так в этом же вся суть EP>Функция автоматически преобразовывается в класс-автомат, и её локальные переменные становятся полями класса. EP>Тоже самое например происходит в показанном ранее примере C# — обрати внимание на исходный код с await, на переменную result, и на поле <result>5__1 в сгенерированном коде V>Я тебе на это уже отвечал — на примере C# видно, что корутина (произвольного размера) создаётся в куче, реализует некий публичный интерфейс, а локально мы имеем лишь ссылку на этот интерфейс.
Ты перескакиваешь с темы на тему. Тут я показываю что локальные переменные прекрасно хранятся в полях класса-автомата.
V>Т.е. для случая расположения корутины на куче у нас не страдает система типов, т.к. мы можем привести корутину к одному из известных типов,
А почему ты считаешь что она страдает в описываемом мной случае? У нас есть доступ к конкретному типу конкретной корутины, и даже известен sizeof — делай с ним что хочешь.
V>воспользовавшись рантайм-полиморфизмом, который работает исключительно и только для ссылочных типов данных.
Рантайм полиморфизм это тоже ортогонально к теме — так как он добавляется совершенно неинтрузивно, смотри примеры std::function и any_iterator.
V>>>Где будет хранится локальная переменная tmp в твоём случае, т.е. когда iterator<> — это полностью value-type объект? EP>>Она будет хранится внутри объекта-автомата, который будет хранится внутри самого итератора. Естественно тип итератора будет зависеть от типа класса-автомата. V>Ну вот на это я и намекал неделей ранее ))
А я где-то говорил другое? Очевидно что zero-overhead без этого никак не получить.
V>В общем, выходит так, что пользоваться такой корутиной можно только через auto,
Нет, это не так. Создаём корутину-генератор — имя класса concrete_generator. Для неё есть функции begin/end возвращающие coroutine_iterator<concrete_generator> — и ничто не мешает выписать вручную этот тип.
V>но не означает ли это невозможность использования сериализации?
Даже если "только через auto" — нет, не означает, так как есть decltype.
Здравствуйте, BulatZiganshin, Вы писали:
BZ>я посмотрел windows.h от win 3.1 — не было там никаких CS и прочих мьютексов.
В Win32s для win 3.1 было.
BZ>и на твой вопрос ответ — нет. при использовании синронных операций работы с файлами это ничем не отличается от записи в одном потоке
Ну я надеялся на вопрос от Ikemefula относительно использования асинхронной записи. ))
Там даже в асинхронном случае ничего такого не надо.
N>Не-а. Я как раз обобщаю до правильного построения вопроса. Call stack — это очень частный случай истории: только те вызовы, которые ещё не редуцировались. Правильный вопрос — что нужно из истории, в общем смысле. Для примера — многие любят отладчик, как средство работы — расставить breakpoint'ы, пройтись пошагово... как только ты выходишь за пределы показа только того же call stack, ты переходишь к рассмотрению истории в широком смысле (в неё будет входить видимый тебе путь выполнения с переменными по ходу и т.п.)
Если так, то согласен. Только с асинхронным кодом эти чудеса вылазят практически сразу.
I>>В многопоточном коде я бы сказал 70-80% проблем решаются с помощью этого фокуса. Если проблема с забытыми ссылками, здесь, опять же, помогает колстек — в том же профайлере.
N>Забытые ссылки — ты явно не то имеешь в виду, что я. Я имел в виду в managed среде то, что не очищается через GC, потому что где-то в сложных данных осталась на него ссылка.
Это оно и есть. Профайлер покажет, по какой цепочке ты выделил эту хрень. Это конечно очень затратный фокус, но в асинхронном коде нет даже и его.
N>>>А что, с остановкой всех тредов ты его не получаешь? I>>Полчаешь, только ручной работы несравнимо меньше"
N>Должно быть больше.
Здравствуйте, Sinclair, Вы писали:
V>>Я предпочитаю озвучить ТЗ, потому что это иначе спекуляции. S>Какое ТЗ? Речь идёт о целом классе задач, у которых есть характерные общие черты.
Это слишком широкая трактовка. Конкретно мы с Ikemefula спорим о таком феномене, как "гонки". А это вполне конкретное событие, не допускающее столь широкого толкования, как ты попытался.
V>>Потому как иначе получается, что ты тоже умудрился много чего проигнорировать, например, то, что сама операция SetRemoteResource должна быть атомарной, например, для случая, когда тип I представлен значением, которое не записывается в своё хранилище за одну операцию процессора. Как эту атомарность обеспечивать будем в случае жабасрипта? S>Ну, если у нас есть готовое решение для обеспечения атомарности всего блока, то уж наверное можно его применить и к отдельной операции, нет?
Ну конечно. Тут можно рассуждать сколько угодно далеко, всё дальше от сути спора о "гонках".
Вот это меня и возмутило в твоём примере... бо он настолько абстрактен, что в него можно впихнуть Всю Сущность Мироздания даже в любимом твоём том самом физическом смысле, бо физические процессы именно таковы и есть — происходят во времени и пространстве, да еще и одновременно (параллельно) ). Вот и всё что ты сказал в том посте. ))
V>>Вопрос, нужны ли в случае жабасрипта критические секции, мьютексы и т.д. для этой задачи? S>Всё зависит от того, есть ли у нас гарантия единственности системного потока, в котором бегут эти логические потоки.
Золотые слова. ))
Об этом уже 3-й год идет спор.
Ну не то, чтобы прям всё время идет... но просто вернулись к одному эпическому спору.
Я однажды ляпнул, что если вся кооперативная многозадачность сидит на одном потоке ОС, типа как в ГУИ или в жабаскрипте, то можно построить код так, чтобы критические секции (и прочие мьютексы/семафоры) были не нужны. Теперь Ikemefula бегает за мной по всем форумам, вызывая на продолжение того спора. Но я уже, если честно, пожалел о том, что поддался на провокации. )) Потому что еще в тот раз было дано объяснение с намного большей степенью подробности, чем сейчас.
S>Потому что если вдруг VM начала использовать N потоков (или если мы тупо запустили 2 инстанса VM на одной машине), то без примитивов мы получаем гарантию мусора.
Да. Вот именно поэтому я уделил приличную часть этого поста
рассуждениям о том, что есть "контекст" в жабаскрипте и почему к одному "контексту" обязательно будет только один системный поток в один момент времени... даже если у нас VM многопоточная, как Node.js. Эти гарантии даются языком ECMAScript в неявном и явном виде.
S>Да, это так. Но вот эту уверенность лучше основывать на чём-то надёжнее, чем "я пока ни разу такого не видел".
Дык, у нас любой код пляшет от неких гарантий. Например, GUI-поток в виндах. Это же тоже гарантия, не? Ты же наверняка поупражнялся достаточно в GUI на клиентских приложениях в своё время? Думаю, ты пользовался знанием о том, где у тебя GUI-поток, а где нет. Более того, даже если в приложении было больше одного GUI-потока, ты всё-равно понимал детали происходящего. Например такие, что к некоторому окошку придут сообщения только из того потока, в котором это окошко создано.
С дотнетом 4.0 и выше идут 3 шедуллера Task-ов в комплекте, и об одном из них так и говорится — вот этот шедуллер основан на GUI-очереди сообщений, со всеми сопутствующими гарантиями. Пользуйтесь, если желаете.
S>Потому что я видел много "многопоточного" кода, который уверенно работал ровно до момента запуска на многоядерной машине.
Ну значит, он не работал и на одноядерной. ))
Потому что прерывания ядра — они такие, беспощадные, сцуко.
Бывают даже посреди операции i++.
Просто вероятность проявления ошибок на одноядерной машине была низка. Низкая вероятность проявления ошибки и отсутствие ошибки — это две большие разницы. Я же веду рассуждения именно об отсутствии ошибки в том, чтобы полагаться на однопоточный доступ к "контексту" жабаскрипта. Это как окно GUI — для каждого отдельного окна GUI гарантируется вызов событий только в одном системном потоке в один момент времени... Даже если этот поток переползет на другое ядро в процессе своей жизни. Точно так же и Node.js, даже если событие к некоему контексту будет обработано потоком из пула потоков, гарантируется, что в один момент времени контекст будет выполнять свой скриптовый код только из одного потока.
S>Ну, для этого придётся специально постараться. Но это будет ожидаемым поведением — важное выделено. В наивной реализации блокируюшего IO заблокируется вообще весь мир, а не только зависимые таски.
Традиционно блокирующее IO используется только в приватных потоках. Поэтому весь мир прекрасно живет даже в случае блокирующих потоков. И я не хочу спорить тут о сценариях, когда это плохо (твои 10тыщ соединений к серваку), бо намного больше сценариев, когда это работает намного-намного эффективней асинхронного ввода-вывода (раза в 2-3). Я как раз по работе этим занят. Кароч, под разные сценарии подходят разные решения.
В любом случае, это всё ушло далеко от первоначального спора. Потому что тому, что ты утверждаешь, у меня нет поля для возражения — только для уточнения. В общем, здравствуй переливание из пустого в порожнее.
S>Просто обычно вытесняющая многозадачность — адски дорогая. Поэтому лучше иметь кооперативную многозадачность с примитивами синхронизации.
Ну, стоимость вытесняющей многозадачности уровня ОС в точности равна стоимости пользования примитивами синхронизации уровня ОС.
Потому что дороговизна "традиционной" вытесняющей многозадачности складывается из следующих составляющих:
— смена юзверского контекста на ядерный;
— "тупой шедулер"; тупой, потому что ему недоступны прикладные зависимости м/у потоками, поэтому системный шедуллер каждый божий раз пробегается по ВСЕМ ожидающим примитивам синхронизации в надежде отыскать поток, который уже пора разбудить;
Поэтому-то CRITICAL_SECTION в 99.9% случаев обходится простым InterlockedCompareExchange и InterlockedIncrement, а создаёт ядерный семафор только в случае относительно долгого конфликта на ресурсе (такого, который не успел рассосаться за время spin-wait).
Вернемся к кооперативной асинхронщие.
Если использовать "асинхронные мьютексы", как предлагает Ikemefula, то мы поимеем аналог описанного "тупого шедулера" в полный рост.
Именно поэтому в асинхронщине более принято явно обозначать зависимости м/у задачами, а не "огораживать" ресурсы.
Например, в моём ТЗ относительно "одновременных" записей сообщений в файл, этот файл НЕ НАДО лочить никаким асинхронным мьютексом, надо просто создать выделенный асинхронный процесс записи в файл, т.е. назначить файлу одного "владельца" и создать очередь из объектов-сообщений для записи в файл (или же из их сериализованных в байты тел — на вкус и цвет, как грится), где выделенный процесс будет эту очередь разгребать. Вот так решаются подобные задачи в асинхронщине — через зависимости. Потому что, если очередь пуста, то операция записи в такую очередь породит зависимость
(см function onKeyboard(nextChar) в сниппете по ссылке), — считай "разбудит" тот самый выделенный процесс, который пишет в файл. В этом и суть — что не шедуллер каждый раз проверяет "асинхронный мьютекс", (а на деле — вхолостую запускает задачу, а она, после обнаружения холостого запуска ставит сама себя в конец очереди и так бесконечно по кругу), вместо этого тупого алгоритма мы по-умному должны "разбудить" асинхронный процесс тогда и только тогда, когда ему есть что делать. И я вижу тут замечательнейшую на 100% надежную детерминированность и отсутствие всяких гонок.
Здравствуйте, vdimas, Вы писали:
V>Т.е. лямбда создаётся на стеке, но при сохранении её в std::function, происходит создание её копии в куче, потому что объект function устроен как-то так (схематично):
Естественно оно будет в общем случае в куче, так как происходит стирание типа, и соответственно размера.
EP>>И почему stackless корутина должна размещаться в каком-то другом месте? V>Потому что, как и в случае std::string, для которого тоже есть некая оптимизация "маленьких" значений, реальный размер корутины заранее предугадать невозможно.
Это "потому что" никак не отвечает на поставленный вопрос. При стирании типа (как в std::function или .then), это справедливо и для передачи замыкания-лямбды, и для передачи корутины.
Как ответ на вопрос нужно показать чем объект-корутина отличается от лямбды в этом контексте, и почему её нужно размещать в другом месте. Ты же привёл общую для них характеристику, никак не обосновывающую необходимость отличий при размещении.
V>>>Я бы его разместил в объекте-наследнике того самого shared_state, который, в свою очередь, создаётся на куче. EP>>А здесь можно вообще не менять ни сам future, ни лезть в его внутренности (типа наследования от shared_state). Потому что используем ли мы обычные продолжения, или объект-автомат (ручной или сгенерированный stackless coroutine) — это совершенно ортогонально тому где мы их размещаем. V>Если используем future, то у нас в любом случае будет выделение памяти из кучи. Я лишь предлагаю свести кол-во выделений к минимуму, реализовав корутину как наследника future, либо как в случае с make_shared, просто расположив оба объекта в одном куске памяти (что фактически идентично с т.з. использования памяти). И я УВЕРЕН, что это именно так и будет. Даже могу поспорить на денюжку. )) Сорри, но это слишком очевидно, чтобы это "промухать". Не промухают, я уверен.
Подобная оптимизация возможна и для обычных замыканий, и для объектов-корутин которые я предлагаю — так как внутри .then мы знаем их размер, и можем аллоцировать их вместе с другими аллоцируемыми объектами за одну аллокацию (как в make_shared). Причём код оптимизации будет идентичным для обоих случаев, и авторам этой оптимизации вообще ничего не нужно знать о том что существуют ещё какие-то корутины.
В случае же proposal от microsoft, корутина аллоцируется своим отдельным аллокатором. И даже если оптимизация подобная make_shared и возможна — то автор future должен знать о том что у замыкания есть свой аллокатор, и писать отдельный код для этого случая.
Причём это относится не только к какой-то одной реализации future — а ко всем подобным. Специальный код должен быть в каждом случае.
EP>>Ты понимаешь что над корутинами из Boost.Asio можно сделать обёртку-итератор, в котором полностью будет хранится вся корутина? Или показать пример? V>Не надо пример. Я, как раз, понимаю о чем речь, но ты не вникаешь в суть моих вопросов. Я всегда спрашиваю одно и то же — какой будет тип результирующего объекта?
— у корутины есть тип, имя этого типа задаётся объявлении корутины, то есть struct coroutine, или с синтаксическим сахаром — future<void> coroutine().
Это обычный тип, никакой магии.
V>Можно ли объявить переменную этого типа БЕЗ объявления корутины, а реальную корутину присвоить "потом" — как в твоём сценарии сериализации?
Конечно можно — это банальное type erasure, такое же как и в std::function.
V>>>Если твоя легковесная корутина будет содержать в себе другие корутины, то нужно эмулировать стек для их правильного обхода. И тут уже, извини, но без выделения памяти в куче — никак. EP>>Зачем? V>Для рекурсии. В т.ч. всевозможной неявной, через вызовы, скажем, захваченных в лямбду методов-переменных.
Только в случае корутинной рекурсии. То есть:
1) если в корутине вызывается обычная рекурсивная функция типа quicksort — то используется стандартный стэк.
2) если в корутине вызывается другая корутина, без рекурсии, то никакой динаимики — размер обеих известен во время компиляции.
3) если происходит простой рекурсивный вызов корутины, то получим ошибку incomplete type, который обходится динамикой, конкретнее — стэком корутин.
Не вижу в этом проблемы. В proposal от Microsoft динамика же будет во всех трёх случаях.
EP>>Вложенная корутина будет просто полем объекта внешней корутины V>Ты забыл, что корутина у нас stack-less, поэтому стек ей придётся нарисовать ручками. И этот стек — штука динамическая, увы)) V>Поэтому — в куче.
Только в случае рекурсивных корутин
EP>>Вот пример, в нём нет никаких аллокаций в куче V>(скипнул пример) V>В этом примере нет, ес-но. Потому что нет недетерминированного стека вызовов.
А в proposal от Microsoft есть аллокации, хотя их вообще тут не должно быть.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
V>>Я тебе на это уже отвечал — на примере C# видно, что корутина (произвольного размера) создаётся в куче, реализует некий публичный интерфейс, а локально мы имеем лишь ссылку на этот интерфейс.
EP>Ты перескакиваешь с темы на тему.
Здравствуйте, vdimas, Вы писали:
V>Например, в моём ТЗ относительно "одновременных" записей сообщений в файл, этот файл НЕ НАДО лочить никаким асинхронным мьютексом, надо просто создать выделенный асинхронный процесс записи в файл, т.е. назначить файлу одного "владельца" и создать очередь из объектов-сообщений для записи в файл (или же из их сериализованных в байты тел — на вкус и цвет, как грится), где выделенный процесс будет эту очередь разгребать.
Такая очередь, если выделить её в отдельный компонент/функцию, и будет тем самым мутексом или семафором.
var operation = queued('resourceId', operationImpl, 2);
// последний аргумент - количество одновременных тасков, 1 = мутекс, >1 = семафор
//в разных задачах можно спокойно вызывать operation
(см function onKeyboard(nextChar) в сниппете по ссылке), — считай "разбудит" тот самый выделенный процесс, который пишет в файл. В этом и суть — что не шедуллер каждый раз проверяет "асинхронный мьютекс", (а на деле — вхолостую запускает задачу, а она, после обнаружения холостого запуска ставит сама себя в конец очереди и так бесконечно по кругу)
Асинхронному мутексу не надо ничего проверять. Он извлекает колбек из очереди и вызывает его. Если вызывающий код был готов писать в файл, то это значит, что все конкурирующие задачи или отработали или еще не начинали, а стало быть ресурс свободен.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>>>https://msdn.microsoft.com/en-us/library/dd998369.aspx I>>Так себе. Win.js применяется чуть менее чем нигде, а бОльшую часть js кода вижла даже дебажить толком не умеет.
НС>Я не знаю что там с JS, но для дотнета этот тул показывает вполне подробную картину.
Я в курсе, но это не интересно, потому что речь шла про JS, в частности — Node.
Здравствуйте, Ночной Смотрящий, Вы писали:
I>>Я в курсе, но это не интересно, потому что речь шла про JS, в частности — Node.
НС>Тем не менее сей тул показывает принципиальную возможность решения проблем и для JS.
Это неинтересно. В отладке имеет значение только то, что у тебя под рукой.
Здравствуйте, Ночной Смотрящий, Вы писали:
I>>Это неинтересно. В отладке имеет значение только то, что у тебя под рукой.
НС>Что то я не видел в предыдущем твоем вещании упоминания того, что это касается проблем конкретного инструментария.
Намекаешь, что мне в каждом сообщении напоминать, что я говорю в основном про нод ?
Здравствуйте, Ikemefula, Вы писали:
I>А как по твоему два процесса смогут работать с одним файлом, что бы гарантировать определенную последовательность записей ? I>
а ровно так же, как и один процесс. просто не использовать yield в середине логичексой операции
Здравствуйте, vdimas, Вы писали:
BZ>>я посмотрел windows.h от win 3.1 — не было там никаких CS и прочих мьютексов.
V>В Win32s для win 3.1 было.
win32s — это эмуляция win32 поверх win16, и оно там понадобилось ровно для того чтобы больше приложений написанных для nt, могло под win3.1 работать. но реализация была видимо такая как я изложил
BZ>>и на твой вопрос ответ — нет. при использовании синронных операций работы с файлами это ничем не отличается от записи в одном потоке
V>Ну я надеялся на вопрос от Ikemefula относительно использования асинхронной записи. )) V>Там даже в асинхронном случае ничего такого не надо.
я так понимаю, под асинхронными тут понимаются всё та же кооперативная многопоточность, просто с колбеками вместо сопрограмм, что на ответ не влияет
Здравствуйте, Ikemefula, Вы писали:
I>Я не знаю, как именно отработали, но базовые примитивы синхронизации были в виде с самого начала, как только там появилась возможность запускать более одного процесса.
винда изначально была графической оболочкой, загружавшей несколько сопрограмм из разных exe-файлов. и весь api там был сконцентрирован на графике, очереди сообщений, перемещаемой памяти (для real mode). из всех "примитивов синхронизации" — только Yield()
а файловые локи появились где-то в dos 3.2 для работы с файлами в сети, и поддерживались всякими сетевыми клиентами, а не виндой