Yoda писал(а):
Это лишь недостаток конкретной реализации. Мы же обсуждаем идеологию.
Я отвечал на конкретный вопрос. В случае, если Вы уменьшите объём стека, уменьшится и пустой расход памяти, это самоочевидно. Однако по-любому её будет тратиться намного больше, чем для одного стека ядра + памяти под контексты потоков -- а это как раз идеология.
SII писал(а):
А мне как раз кажется, что лучше стек для каждого потока. Ведь всё равно состояние потока нужно где-то сохранять. Либо переносить данные из общего стека в область данных конкретного потока, либо ничего не переносить, а переключать стек. Второй способ мне представляется более простым и надёжным.
Ещё и ещё раз. Стек ядра на каждый поток -- большой лишний расход памяти. Каждый такой стек должен иметь размер, не уступающий максимальным потребностям системы в стеке (ведь нельзя заранее сказать, когда весь этот объём понадобится). Поэтому в Линухе и отвели 8 Кбайт -- чтоб точно хватило. Но даже если отводить под собственно стек, без учёта области сохранения (она, понятное дело, одинакова при любом способе хранения), всего 1 Кбайт, то при 100 потоках получим уже 100 Кбайт, которые реально не используются, а лишь впустую занимают память. А 100 потоков -- это ерунда. В моей винде-7 сейчас, например, 965 потоков -- получается, впустую вылетит почти мегабайт. Правда, на машине с 12 Гбайтами ОЗУ это кажется несерьёзным, но это всегда отрицательно влияет как минимум на производительность (кэш не резиновый, и если единственный стек ядра с приличной вероятностью будет там находиться "хронически", поскольку используется при каждом прерывании, то вот в случае с кучей стеков ядра они будут постоянно друг друга там затирать). Кроме того, не всегда имеются машины с большим объёмом памяти.
SII писал(а):
Я думаю, что любая прогрессивная система рано или поздно придёт к состоянию "тяжкого наследия". Более того, я совсем не уверен, что возможно выработать единственно правильную систему, архитектуру или какой-то алгоритм, т.к. всё время появляются какие-то новые факторы, которые тяжело или невозможно предвидеть.
Уних никак нельзя отнести к прогрессивным системам даже на момент создания, но об этом говорить не будем -- как-никак, это конкретная вещь, а не идеология в чистом виде :) Что же касаемо последней, то, если не расширять бездумно, изначально хорошая система такой и останется; тем не менее, проблема модернизации, конечно, имеется. Что единственно правильной архитектуры без конкретизации требований быть не может, это тоже достаточно очевидно: ОС не в вакууме работает и оперирует не сфероконями. Но даже для чётко сформулированных требований, наверное, нельзя предложить идеальное решение: всё равно будут какие-то компромиссы, которые могут сыграть в хорошую или плохую сторону в зависимости от реальных условий. Однако можно подойти и с другого конца: хотя однозначно наилучший вариант предложить вряд ли возможно, всегда имеются явно неудачные варианты, которые следовало бы отбросить изначально.
К таким откровенно неудачным решениям относится принудительная "синхронизация" ввода-вывода, что имеет место, похоже, во всех системах, восходящих к Униху, в т.ч. и в Линухе. Причины, почему это однозначно неудачное решение: а) ввод-вывод по природе асинхронен, и обеспечение гарантированной синхронности требует лишних телодвижений, т.е. раздувания и усложнения системы; б) возможность асинхронного ввода-вывода даёт задачам дополнительную гибкость, которую можно использовать для повышения производительности (простой пример я приводил пару дней назад); в) наконец, если задаче не нужна асинхронность, она элементарнейшим образом преобразует его в синхронный, в то время как обратное преобразование невозможно в принципе. В общем, получается, что система с асинхронным вводом-выводом сама по себе будет проще, чем система с синхронным (отпадает нужда в принудительной "синхронизации" изначально асинхронных вещей), и в то же время она предоставит задачам больше возможностей -- т.е. мы имеем очень редкий случай, когда для повышения функционала требуется не усложнить, а упростить реализацию :)
Один стек ядра или много -- это более сложный вопрос. В случае, если ОЗУ мало (например, на микроконтроллерах, даже весьма мощных: так, 400-МГц AT91SAM9G45 имеет всего 64 Кбайта встроенного ОЗУ, куда надо ещё и саму систему с программами впихнуть, поскольку флэш-памяти у него нет -- ну или городить систему с внешней памятью, что удорожает конструкцию, увеличивает её габариты, массу и энергопотребление), много стеков ядра -- это однозначно плохо, поскольку расход памяти становится критически важным. В системах, где ОЗУ хоть залейся (современные ПК), вопрос не столь однозначный. Использование единственного стека ядра со 100% вероятностью гарантирует экономию памяти (обсуждалось выше) и практически гарантирует несколько более высокую производительность (если её не убить чем-либо другим, но будем исходить из "прочих равных") за счёт более эффективного использования кэша, а значит, уменьшения числа реальных обращений к памяти, причём, чем выше производительность процессора, тем больше выигрыш (другое дело, что освободившееся время не всегда бывает, куда деть: 6 ядер моего нынешнего халявного проца явно не шибко перетруждаются во время набора мною сего опуса :) ; кроме того, выигрыш будет отнюдь не в разы, а, может, на пару процентов -- это сильно зависит от интенсивности поступления прерываний, ведь именно тогда идёт переключение стеков). Со сложностью реализации вопрос интереснее. С одной стороны, много стеков допускают "тупой" подход: сохрани контекст в стеке, делай дальше, что хочешь, а если нужно -- вообще усыпи ядро с этим стеком и включи другой стек для обслуживания чего-то другого. Однако, с другой стороны, когда важная информация "складируется" таким неявным образом (в локальных переменных процедур, которые как раз располагаются в стеке), намного выше вероятность возникновения трудноуловимых ошибок, связанных со всякими взаимными блокировками. Например, обработчик захватил какой-то ресурс, сохранил ссылку на него в своей переменной и пошёл что-то делать дальше. В этот момент его прерывает другой обработчик и желает тяпнуть (возможно, косвенно) тот же самый ресурс -- и в результате мёртвая блокировка системы. Когда же вся информация складируется в явно выделенной для этого структуре данных, а не в обычных рабочих переменных, вероятность возникновения такой проблемы меньше: программист просто больше уделяет этому внимания (надо ж описать структуру, выделить под неё память, заполнить, освободить -- глядишь, и не забудет, что в какой-то момент надо, например, прерывания запретить). Так что, ИМХО, тут лишние "телодвижения" окупаются.
Цитата:
Я собс-но возражал против другого. И Linux, и Windows, и все остальные ОСи не пинали разве только ленивые. Их недостатки многим понятны, но наша задача — создание новых концепций или выборки хорошо зарекомендовавших себя, а не пинания старых за очевидные недостатки. Поэтому, как говорится, "ну их всех в топку" :).
Ну дык... Я что, против? Весь сыр-бор, собственно, из-за того, что некоторые выбирают, на мой взгляд, не просто не самый лучший, а откровенно крайне плохой вариант, беря за образец, по всей вероятности, как раз пинаемый мною Линух. Т.е. речь как раз о выборе хорошо зарекомендовавших себя идей (придумать что-то новое почти нереально: такового, по большому счёту, не случалось уже лет 40, наверное; во всяком случае, если отбросить плуг-энд-плей и энергосбережение, не имеющие прямого отношения к архитектуре и осей, то я вообще не знаю ни одной жизнеспособной "осеписательской" идеи, появившейся после примерно 1970-го года).