Windows многозадачная или однозадачная операционная система почему

Обновлено: 25.06.2024

Операционная система – это комплекс программ, обеспечивающих управление работой компьютера и его взаимодействие с пользователем.

С точки зрения человека операционная система служит посредником между человеком, электронными компонентами компьютера и прикладными программами. Она позволяет человеку запускать программы, передавать им и получать от них всевозможные данные, управлять работой программ, изменять параметры компьютера и подсоединённых к нему устройств, перераспределять ресурсы. Работа на компьютере фактически является работой с его операционной системой. При установке на компьютер только операционной системы (ОС) ничего содержательного на компьютере также сделать не удастся. Для ввода и оформления текстов, рисования графиков, расчёта зарплаты или прослушивания лазерного диска нужны специальные прикладные программы. Но и без ОС ни одну прикладную программу запустить невозможно.

Операционная система решает задачи, которые можно условно разделить на две категории:

  • во-первых, управление всеми ресурсами компьютера;
  • во-вторых, обмен данными между устройствами компьютера, между компьютером и человеком.

Кроме того, именно ОС обеспечивает возможность индивидуальной настройки компьютера: ОС определяет, из каких компонентов собран компьютер, на котором она установлена, и настраивает сама себя для работы именно с этими компонентами.

Ещё не так давно работы по настройке приходилось выполнять пользователю вручную, а сегодня производители компонентов компьютерной техники разработали протокол plug-and-play (включил - заработало). Этот протокол позволяет операционной системе в момент подключения нового компонента получить информацию о новом устройстве, достаточную для настройки ОС на работу с ним.

Операционные системы для ПК различаются по нескольким параметрам. В частности, ОС бывают:

  • однозадачные и многозадачные ;
  • однопользовательские и многопользовательские ;
  • сетевые и несетевые .

Кроме того, операционная система может иметь командный или графический многооконный интерфейс (или оба сразу).

Однозадачные операционные системы позволяют в каждый момент времени решать только одну задачу. Такие системы обычно позволяют запустить одну программу в основном режиме.

Многозадачные системы позволяют запустить одновременно несколько программ, которые будут работать параллельно.

Главным отличием многопользовательских систем от однопользовательских является наличие средств защиты информации каждого пользователя от несанкционированного доступа других пользователей. Следует заметить, что не всякая многозадачная система является многопользовательской, и не всякая однопользовательская ОС является однозадачной.

В последние годы фактическим стандартом стал графический многооконный интерфейс, где требуемые действия и описания объектов не вводятся в виде текста, а выбираются из меню, списков файлов и т.д.

В настоящее время, с появлением мощных компьютеров, широкое распространение получили два типа ОС. К первому типу относятся достаточно похожие ОС семейства Windows компании Microsoft. Они многозадачные и имеют многооконный графический интерфейс. На рынке персональных компьютеров с Windows конкурируют ОС типа UNIX . Это многозадачная многопользовательская ОС с командным интерфейсом. В настоящее время разработаны расширения UNIX, обеспечивающие многооконный графический интерфейс. UNIX развивалась в течение многих лет разными компаниями, но до недавнего времени она не использовалась на персональных компьютерах, т.к. требует очень мощного процессора, весьма дорога и сложна, её установка и эксплуатация требуют высокой квалификации. В последние годы ситуация изменилась. Компьютеры стали достаточно мощными, появилась некоммерческая, бесплатная версия системы UNIX для персональных компьютеров - система Linux . По мере роста популярности этой системы в ней появились дополнительные компоненты, облегчающие её установку и эксплуатацию. Немалую роль в росте популярности Linux сыграла мировая компьютерная сеть Internet. Хотя освоение Linux гораздо сложнее освоения систем типа Windows, Linux - более гибкая и в то же время бесплатная система, что и привлекает к ней многих пользователей.

Существуют и другие ОС. Известная компания Apple производит компьютеры Macintosh с современной ОС MacOS . Эти компьютеры используются преимущественно издателями и художниками. Фирма IBM производит ОС OS/2 . Операционная система OS/2 такого же класса надёжности и защиты, как и Windows NT.

В комментариях к статье "Цикл (операция) Чтение-Модификация-Запись. Как это работает", в очередной раз, была затронута тема использования стандартных средств компилятора для работы с внешними данными, включая аппаратные ресурсы. Причем проводилась, в некоторой степени, параллель между данными разделяемыми разными потоками или приложениями и данными аппаратными.

Об этом написано многое и многими. В том числе, есть статьи и на моем канале. Но тема действительно сложная и вызывает множество дискуссий и вопросов. Поэтому я решил предпринять еще одну попытку рассказать, как это работает, и почему все так не просто. И почему неверно проводить параллели между работой с разделяемыми данными и аппаратными ресурсами.

Другими словами, статья будет о программировании не прикладном, и даже не совсем системном. Она будет о той тонкой грани, которая связывает работу аппаратуры и программы. Безусловно, это затрагивает далеко не не всех. Можно было бы сказать, что это и интересно то очень мало кому. Но сегодня, когда все больше используются микроконтроллеры, круг тех, кого это касается, стал шире.

И это будет скорее обзорная статья. И несколько сумбурная, скорее всего. Для тех, кто никогда раньше с такими вопросами не сталкивался.

Ссылки на статьи:

Процессоры, ядра, машины, комплексы

В сегодняшней статье будет постоянно употребляться термин машина . Безусловно, в общем случае речь идет именно о вычислительной машине. Но почему не просто ЭВМ? В чем то, это дело многолетней привычки привычки. Но не то только. Дело в том, что ЭВМ это именно вычислительная машина, которая когда то занимала целые залы, но постепенно уменьшилась до блока в стойке или даже одной печатной платы в крейте.

ЭВМ может быть управляющей. Но такие машины все равно оставались именно вычислительными машинами. Но со временем появились и встраиваемые ЭВМ. И такая машина уже далеко не всегда использовалась именно для вычислений. Персональные ЭВМ, те самые ПК, всех сортов и мастей. Но и однокристальные ЭВМ, именно так изначально называли микроконтроллеры. Смартфоны, которые уже трудно назвать ЭВМ.

Термин машина является обобщающим. Он включает в себя и аналоговые, и аналогово-цифровые (были и такие), и классические цифровые (ЦВМ), и управляющие, и встраиваемые ЭВМ. И микроконтроллеры, и смартфоны. И даже релейные автоматы.

Конечно, АВМ, АЦВМ и релейные автоматы сегодня рассматриваться не будут. Кстати, термин ЭВМ тоже обобщающий. Он включает в себя АВМ, АЦВМ, ЭЦВМ (именно их обычно имеют ввиду, когда говорят ЭВМ).

Но все это означает, что машины могут быть очень разные. Давайте кратко рассмотрим основные варианты, которые сегодня использоваться в статье. Разумеется, все они будут цифровыми.

Классическая ЭЦВМ, она же ЦВМ, она же ЭВМ

Классическая электронная цифровая вычислительная машина - ЭЦВМ. Иллюстрация моя Классическая электронная цифровая вычислительная машина - ЭЦВМ. Иллюстрация моя

ПУ это периферийные устройства. И, по большому счету, они являются внешними по отношению к собственно ЭВМ. А вот каналообразующее оборудование (контроллеры, канальные процессоры, и т.д.) входит в состав ЭВМ. И все вместе это машина.

ПДП это канал прямого доступа к памяти. Он позволяет внешним устройствам обмениваться с ЭВМ данными не занимая процессор. И, как мы скоро увидим, это тоже может стать источником проблем.

Многопроцессорная ЭЦВМ

Просто так добавить процессоры не получится. Их работу нужно синхронизировать, что бы не возникало конфликтов. В частности, конфликтов при доступе к памяти. Подробности построения многопроцессорных машин нам сегодня не важны. Поэтому просто будем считать, синхронизация обеспечивается специальным устройством синхронизации.

В такой конфигурации память является критическим ресурсом, так как быстродействие машины в основном определяется быстродействием памяти. Ведь все процессоры выполняют программы хранящиеся в памяти. И данные хранятся там же.

Однако, и коды программ, и данные, обрабатываемые разными процессорами, обычно располагаются в разных областях памяти. А значит, мы можем избежать, по крайней мере, части, конфликтов разбив память на отдельные блоки. А устройство синхронизации будет отслеживать запросы доступа разрешая одновременный доступ разных процессоров к ячейкам памяти в разных блоках.

Такая организация доступа к общей памяти называется многопортовой памятью. Она не позволяет полностью избежать конфликтов, но значительно повышает общее быстродействие машины снижая влияние быстродействия памяти.

Другим способом повышения быстродействия машины является введение дополнительных блоков памяти небольшого объема для каждого отдельного процессора. Такую память обычно называют кэш памятью. В кэш память позволяет обращаться к основной памяти для обмена целыми блоками, а не отдельными байтами (словами).

Кэш подключается к процессору через специальный контроллер. Я не буду отдельно иллюстрировать эту конфигурацию.

Обратите внимание, что в многопроцессорной машине каналы ПДП не работают с памятью напрямую. Любой доступ к памяти должен осуществляться только через устройство синхронизации. На самом деле, синхронизация требуется в однопроцессорных машинах.

Многоядерные процессоры

Если объединить несколько процессоров, вместе с кэш памятью и устройством синхронизации, в единое целое, то мы получим многоядерный процессор.

Конфигурация многоядерных процессоров может быть различной, очень различной. Обычно, ядра размещают на одном кристалле, или в одном корпусе. Что позволяет значительно уменьшить размер машины. Кроме того, многоядерный процессор часто строится по более простой схеме, чем многопроцессорная машина.

Для нас детали сегодня не важны. Мы можем считать, что многопроцессорная машина и машина с многоядерным процессором практически одинаковы. Разумеется, машина может содержать и несколько многоядерных процессоров.

Однако, одно небольшое отличие, важное для нас сегодня, все таки есть. Многопроцессорная машина может работать под управлением нескольких ОС (операционных систем) одновременно. Это далеко не самый распространенный случай, но такое бывает. Машины с многоядерными процессорами обычно работают под управлением одной ОС. Не смотря на то, что теоретически разные ядра могут выполнять разные ОС, такое практически не встречается. из-за архитектурных особенностей многоядерных процессоров.

Запуск разных ОС на разных ядрах возможен под управлением гипервизора. Но в этих случаях говорят о виртуальных машинах. Этот вопрос выходит за рамки сегодняшней статьи.

Многомашинный комплекс

Несколько машин, причем разных, могут быть объединены в единый комплекс. Это можно сделать различными способами. Причем далеко не только с использованием сетей, как сегодня думают очень многие.

Классический многомашинный комплекс использует специальные каналы связи, которые ближе системным шинам. И такие каналы связи могут иметь и собственную общую память, и собственные общие периферийные устройства

Многомашинный комплекс с общей областью памяти и периферийными устройствами. Иллюстрация моя Многомашинный комплекс с общей областью памяти и периферийными устройствами. Иллюстрация моя

Чем нам сегодня интересен многомашинный комплекс? В первую очередь, именно этим общим, межмашинным, блоком памяти. Причем эта память может просто отображаться на часть адресного пространства каждой машины. То есть, с точки зрения прикладной программы, эта память будет неотличима от памяти машины. Все дополнительные заботы возьмет на себя аппаратура межмашинного интерфейса.

Операционные системы, многозадачность, многопоточность

Операционная система является связующим звеном между оборудованием машины и прикладной программой (задачей). Точнее, таким связующим звеном являются драйверы оборудования, входящие в состав ОС.

Но драйверы это лишь малая часть ОС. Значительную часть составляют механизмы управления задачами (переключение, синхронизация, и т.д.), механизмы безопасности и доступа, высокоуровневые сервисы (например, сетевой стек). Подробности архитектуры ОС нас сегодня не интересуют, но некоторые моменты кратко рассмотрим.

Кстати, ОС без драйверов тоже существует. В своем простейшем варианте такой ОС можно считать программы-мониторы, которые использовались в первых ПК вроде "Радио-86РК", "Микро-80", и им подобных, включая зарубежные.

BIOS в IBM/PC наоборот, можно считать лишь набором простейших драйверов, без системного сервиса. Не смотря на то, что BIOS обеспечивает и интерфейс с пользователем, и загрузку ОС, сам его ОС считать нельзя.

Однозадачная ОС

Простейший вариант ОС, который сегодня можно встретить очень редко. По сути, это программа-монитор с небольшим набором драйверов. Она позволяет запускать только одну задачу, но предоставляет ей небольшой системный сервис. При этом есть возможность загрузки дополнительных драйверов внешних устройств.

Но для нас самым важным является именно однозадачность. На первый взгляд, это полностью избавляет от проблем совместного доступа к разделяемым ресурсам. Но все не так просто!

Да, в данном случае программа (задача) работает только со своими собственными данными, другой, параллельной, задачи просто не может быть. Или может? А ведь действительно может! Сама ОС это именно параллельная задача. Как и любой драйвер, который работает по прерываниям.

Проблем не возникнет, если прикладная задача получает доступ к ресурсам ОС только через специально предусмотренные запросы к ОС. Такими ресурсами являются, например, текущие дата и время, файловые буферы, системные таблицы. Любая попытка прямого доступа, игнорируя ОС, может привести к ошибке.

Вспомните MS-DOS, сколько программ работало с ее внутренними областями памяти напрямую. При соблюдении строгих правил это было, пусть и условно, безопасно. Запрет прерываний не единственное условие, и сама ОС должна при этом быть в устойчивом состоянии. Это требовало дополнительных проверок.

Вся забота о синхронизации в таких системах лежит на программисте, если он решает игнорировать механизмы ОС. На программисте же лежит обеспечение бесконфликтного доступа к разделяемым сетевым ресурсам. Но эти случаи нам сегодня не интересны.

Но нам интересна работа с аппаратными ресурсами. Пока предположим, что прикладная программа не работает непосредственно с оборудованием. Но это не избавляет от некоторых нюансов.

Например, программа создала буфер для работы с диском, зарезервировала для него место в памяти. Работа с диском выполняется через ОС, что безопасно (на первый взгляд). Но при обращении к ОС для чтения/записи буфера программа может запросить асинхронное выполнение запроса. Или такое поведение подразумевается ОС по умолчанию. И мы получим параллельное выполнение прикладной программы и ОС (драйвера).

Вы наверняка скажете, что программист (прикладной!) должен знать об особенностях ОС и самостоятельно отслуживать необходимы флаги и статусы. И будете правы. Только вот универсальный язык высокого уровня, и его компилятор, не окажут программисту никакой поддержки. Никакие std::atomic (С++) или _Atomic (С) не помогут.

Немного изменим наш пример. Пусть программа работает с контроллером диска напрямую. Теперь у нас исключено влияние ОС и драйвера. Но ведь диск может работать, например, только с использованием ПДП. И мы опять получаем конкурентный доступ к буферу в памяти! Только теперь не две программы выполняются параллельно (псевдопараллельно, процессор то один), программа работает параллельно каналу ПДП, аппаратному средству.

И мы опять должны, вручную, отслеживать флаги, только теперь оборудования. И опять ЯВУ нам никакой поддержки не окажет. Да, обычный прикладной программист вряд ли будет работать с диском минуя ОС (хотя чудеса иногда случаются), но это не отменяет того, что программист будет бороться с оборудованием "в рукопашную".

Многозадачная ОС, один процессор

Многозадачная ОС не всегда будет и многопользовательской. Но многопользовательская всегда будет многозадачной. Мы не будем погружаться в подробности терминологии, как и в подробности собственно многозадачности. Нас будет интересовать синхронизация доступа.

Поскольку процессор всего один, настоящего параллельного выполнения задач не будет. Но ОС создаст иллюзию параллелизма выполняя переключение задач. И к описанным ранее ситуациям добавится возможность нескольким задачам работать с одной и той же областью памяти, с разделяемыми данными.

То, что задачи не выполняются действительно параллельно, ничего не меняет. Сама прикладная программа не может влиять на моменты переключения задач ОС. Исключения есть, например, запрос ввода-вывода может перевести задачу в состояние ожидания до окончания ввода-вывода. Но прямого управления переключением, в современных ОС, нет.

Для синхронизации доступа используются различные способы. Они достаточно широко и подробно описаны во множестве книг и учебников. Поэтому вряд ли имеет смысл уделять дополнительное внимание. Тем не менее, давайте кратко коснемся посмотрим на один метод, который является специфическим для многозадачных ОС на однопроцессорных машинах.

Ранее я говорил, что прикладная задача не имеет возможности влиять на переключение задач. И это действительно так. Но в некоторых ОС может быть возможность временной блокировки переключения. Именно временной, так как иначе злонамеренная задача просто превратит ОС в однозадачную для собственного выполнения.

И мы можем представить примерно такой способ обеспечения безопасного доступа к разделяемым данным

Когда я предложил перевести на русский мою последнюю статью Easy Concurrency with Python Shared Objects на английском, поступило предложение "написать в несколько раз короче и понятнее". Просьба более чем обоснована. Поскольку я уже порядка десяти лет пишу многопоточку и БД, то описываемые мной логические связи выглядели самоочевидно, и я ошибочно расчитывал на аудиторию из трех с половиной человек, которые сидят сейчас где-то в яндексе или гугле. Судя по всему, они там и сидят, но тема им не интересна, поскольку в питоне нет настоящих потоков, а значит для этих людей такого языка программирования не существует. Потому я немножко снижаю планку и делаю общий обзор проблематики параллельных вычислений для людей, которые в них разбираются, но не являются экспертами в области.

Из-за чего весь сыр-бор?

Два процесса выполняются параллельно и независимо. Если мы возьмем первую инструкцию процесса 1, то параллельно с ней может выполниться любая из четырех команд. Вторая команда процесса 1 аналогично не ограничивает выполнение в процессе 2, потому она может выполняться параллельно с любой из четырех команд. Для простоты допускаем, что одна команда атомарна. Всего число возможных сценариев выполнения первого процесса 4^4 = 256. Если в аналогичных первом и втором процессах по десять инструкций, то число различных вариантов выполнения равно 10 10 , то есть, 10 миллиардов. За пару минут мы можем написать 10 миллиардов программ! Вау, мы крутые! А если серьезно, то нам не хватит никакого времени, чтобы отладить все эти 10 миллиардов сценариев выполнения.

По этой причине для успешной реализации параллельных асинхронных задач необходимо беспощадно ограничивать эту параллельность на пересечении задач, в местах согласования и координации.

Что там сложного? Есть конкуренция за ресурс — повесь мьютекс. Я так всегда делаю.

Блокировки, они же семафоры или мьютексы. Если вы только начали осваивать многопоточность в классических императивных языках, то вы знаете про задачу "обедающих философов", и в качестве простейшего решения предложите "официанта", то есть, простую блокировку. Ведь отдельная блокировка на каждую вилку быстро приводит вас к дедлокам.


А еще лучше вообще иметь только одну блокировку на все вилки, ложки, философов, и стол одновременно — создатели питона примерно так и подумали.

Если же вы решили использовать множественные блокировки, то неявные и допускающие вложенность блокировки (Rust std::sync::Mutex или Java synchronized) — путь в никуда, поскольку становится очень легко создать неочевидно дедлочащуюся программу. На самом деле, даже без дедлоков детальные блокировки не являются панацеей, поскольку простые блокировки, они же "семафоры Дейкстры", ограничены в своих способностях:

Хотя задачу курильщиков и возможно решить семафорами Дейкстры, такие "семафоры курильщика" дают сложный в понимании и поддержке алгоритм, при том, что задача, казалось бы, элементарна. Потому вторым по популярности механизмом блокировок стали условные переменные и более общий аспект оных — мониторы (в том числе уже упомянутое Java synchronized). Правда, проблемы дедлоков при множественных блокировках они не решают.

Что же делать? Мы все умрем? Да, но проблему дедлоков можно решить. Одно из остроумных решений для задачи обедающих философов предложил сам Дейкстра — брать детальные блокировки только в одном заранее заданном порядке. Следующий забавный прием — брать блокировки всем скопом одной командой либо отменять взятие блокировки. Такое можно реализовать на любой абстракции с примитивом try-lock (например, compare-and-swap), при помощи бесконечного цикла (например, std::lock из библиотеки C++).


Одна из самых последних и перспективных альтернатив блокировкам — это транзакционная память, по сути атомарный compare-and-swap на большом числе ячеек. Идею транзакционной памяти развил в конкретную программную реализацию, STM, мой любимый автор книг и статей по многопоточности — Нир Шавит. Главное преимущество STM — отсутствие дедлоков. В каком-то смысле транзакционная память достаточно стара, если вспомнить, что реляционные СУБД давно умели в транзакции. Программная транзакционная память, как правило, берет блокировки всем скопом, как в описанном выше алгоритме предварительной блокировки, но делает это не до выполнения операций изменения ячеек памяти, а после — таким образом нам не обязательно до начала работы алгоритма знать список нужных нам блокировок и длительность этих блокировок минимальна. Из популярных готовых решений на эту тему можно вспомнить Clojure и GHC.


У наивной реализации STM есть проблема — при интенсивных конфликтах меж потоками приложение большую часть времени крутит откаты транзакций вхолостую: подробнее.

Решение этой проблемы уже придумано за нас — это алгоритм раннего разрешения конфликтов, при котором реализация не ждет окончания транзакции для того, чтобы осознать невозможность применения ее результатов, а сразу прерывает одну из конфликтующих транзакций. По сути это способ организации детальных блокировок с разрешением дедлоков через откат изменений. Такой подход я и перенял при реализации Python Shared Object.


Коротко: взаимоисключающая блокировка не является основным средством организации доступа к разделяемой памяти и вообще разделяемым ресурсам, но именно этими блокировками чаще всего злоупотребляют.

Подход, известный также как "у меня болит палец — отрежу себе руку!".

Начну издалека. Если мы попытаемся разделить все-все-все алгоритмы и механизмы координации на самые простые винтики и гайки, то получим два основных примитива:

Забавно, что создатель величайшей платформы Erlang для построения распределенных систем, Джо Армстронг, не строит иллюзий и осознает принципиальную неразрешимость проблемы. Вот диаграмма ситуации, которую Армстронг пытался описать на пальцах:


Почему в этот горячий пирожок играют? Потому что идеальное решение невозможно чисто теоретически (FLP-недостижимость) — все практически реализации являются тем или иным компромиссом. Но есть желающие "идеальное решение" купить, потому используется популярный маркетинговый прием: недостатки существующих решений уже хорошо известны, а недостатки нашей новой системы еще не известны… значит можно сказать, что их нет. Так и развиваются многие Big Data проекты.

Когда же у вас есть хотя бы общий атомарный счетчик, а еще лучше — общий атомарный список транзакций, дальше вы можете наращивать объем "нагрузочных данных" как угодно, реплицировать их в eventual consistency хранилищах, придавать им произвольную форму (как это сделало в том же Tango, давшем пользователю свободу выбора формы данных) — это всё имеет второстепенное значение и легко меняется, хотя многие люди по прежнему обращают внимание на обёртку, а не на суть. То есть, ходовые качества машины определяются двигателем, трансмиссией, рулевой системой, но большинство видит лишь красивый кузов и отделку салона, к сожалению. Я хочу здесь подчеркнуть, что ZooKeeper в случае Tango, YandexDB, Calvin, ClickHouse и прочих аналогичных проектов — это не "просто вспомогательная штука", как его рисуют, а ключевой компонент и большая часть сложности реализации всей СУБД, и этот компонент, к тому же, полностью определяет число транзакций в секунду, которые сможет обработать весь кластер.

Золотая середина

Также, сама реализация Erlang/OTP неявно использует разделяемую память. Даже если из питона получится жалкое подобие Erlang — это все равно намного лучше, чем тот безнадежно однозадачный (не путать с зелеными потоками/concurrent IO) интерпретатор питона, который мы имеем сейчас.

Состояние/ячейки данных, используемое для координации, должно быть разделяемым и изменяться строго последовательно. Независимые состояния должны оставаться независимыми, асинхронно выполняющиеся задачи должны выполняться асинхронно. Если лишь часть задач требуют координации, то они и должны разделять некоторую часть состояния для своей координации. Если возможно выполнить одинаковый набор инструкций для большого числа в ячеек в векторе — выполните его при помощи SIMD/CUDA/OpenCL, а не созданием асинхронно выполняющихся потоков, которые потом придется обратно синхронизировать.

Например, оригинальная STM от Нир Шавита использует глобальный атомарный счетчик для координации всех задача, но в остальном "общими" ячейки данных становятся только когда они по-настоящему общие для нескольких задач. Аналогичный подход с общим атомарным счетчиком номера/приоритета транзакции и детальными блокировками также применяет моя реализация STM в виде Python Shared Objects.

Тесты, еще тесты, нужно больше тестов

Как же тестировать и отлаживать многозадачные и распределенные системы? Основная проблема многопоточных, многозадачных, распределенных систем — это недетерминированность их поведения. То есть, ваша система может работать пять лет, а потом резко начать падать из-за какого-то незначительного изменения алгоритма.

В общем случае ответ на вопрос "как тестировать?" — "никак", вы подходите к проблемы с неправильной стороны. Но не расстраивайтесь — это нормально, так делает много кто. По этой причине, например, большинство распределенных СУБД, заявлявших про строгую согласованность данных и отказоустойчивость, в жестких тестах на Jepsen показывают, что на самом деле никогда не обеспечивали как минимум одну из этих гарантий: подробнее.

Тестирование — это способ обнаружить наличие проблемы, но тестированием невозможно доказать отсутствие проблем. Если в качестве отказоустойчивого хранилища согласованных данных вы используете не ZooKeeper и не Etcd, то с большой вероятностью ваша система потеряет/испортит данные или вовсе упадет при потере лидера. Если вы уделите пару часов чтению серии статей по ссылке, то вы узнаете, что какой-нибудь Galera Cluster способен нарушать согласованность даже на полностью исправном кластере, а MongoDB не дает даже "eventual consistency" гарантий при отказах (то есть, в MongoDB ваши данные из подтвержденных транзакций может быть сохранятся, а может быть не сохранятся). Однако, даже если вы построили систему на базе условно надежных ZooKeeper или Etcd, вы не знаете, сколько еще проблем возникло из-за некорректного использования оных в самописном коде.

Единственный более-менее гарантированный способ построить работающую систему — это прежде всего грамотно подойти к ее проектированию и реализации, доказать корректность алгоритма, а не полагаться на популярный нынче метод тестирования и "авось". Вторая линия обороны — это тестирование, но не простое. Разработчики должны понимать, что если ошибка есть, то ее необходимо обнаружить, а не замести под ковер и подпереть костылем. То есть, без участия и сотрудничества самих разработчиков невозможно эффективно произвести тестирование. Необходимо тестировать систему в самых неудобных и опасных режимах, предусмотреть в исходном коде отладочные опции для более частого срабатывания редких фрагментов кода — в том числе такой подход я задействовал для своего проекта Python Shared Objects. В случае отказоустойчивых кластеров обязательно необходимо периодически симулировать отказы, как это делает, например, Яндекс.

Поскольку очень часто проблема происходит только один раз и больше никогда не повторяется, то большую ценность имеет логирование, создание снимков состояния системы во время проблемы. Для последнего, например, есть замечательная утилита rr от Mozilla, которая была разработана специально для отладки многопоточного кода в Firefox. Эта утилита позволяет выполнить код в обратном направлении, точно восстанавливая последовательность выполнения асинхронных потоков, приведшую к ошибке. И хотя облака нынче стали популярным хайпом, выбор инструментов для отладки многозадачного кода и распределенных систем на удивление скудный. Для распределенных систем есть упомянутый Jepsen, для многопоточных есть, например, ThreadSanitizer.

К сожалению, для тестирования моего Python Shared Objects мне так и не удалось найти готового решения для неинтрузивного логирования. Неинтрузивного — поскольку для многопоточного кода имеет место так "эффект наблюдателя" — когда при логировании программа ведет себя совсем не так, как без него. Когда-то давно для закрытой разработки я сам реализовывал неинтрузивное логирование на Delphi, но это было давно и неправда, а на сишные программы этот код довольно плохо налазит.

Коротко: при создании сложных многопоточных, многозадачных, и распределенных систем грамотный подход и такие люди, как я, с большим трудом заменяются тестами и "большой дружной командой".

От эффективности алгоритмов управления локальными ресурсами компьютера во многом зависит эффективность всей операционной системы в целом. Поэтому, характеризуя операционную систему, часто приводят важнейшие особенности реализации функций операционной системы по управлению процессорами, памятью, внешними устройствами компьютера.

Так, например, в зависимости от особенностей использованного алгоритма управления процессором, операционные системы делят на следующие типы:

  • многозадачные и однозадачные;
  • многопользовательские и однопользовательские;
  • системы, поддерживающие многоуровневую обработку и не поддерживающие ее;
  • многопроцессорные и однопроцессорные системы
Классификация операционных систем . Поддержка многозадачности

По числу одновременно выполняемых задач операционные системы могут быть разделены на два класса:

  1. однозадачные (например, MS-DOS, MSX) и
  2. многозадачные (OC EC,OS/2,UNIX, Windows 95/XP/7).

Однозадачные операционные системы в основном выполняют функцию предоставления пользователю виртуальной машины, делая более простым и удобным процесс взаимодействия пользователя с компьютером. Однозадачные ОС включают средства управления периферийными устройствами, средства управления файлами, средства общения с пользователем.

Многозадачные операционные системы , кроме вышеперечисленных функций, управляют разделением совместно используемых ресурсов, таких как процессор, оперативная память, файлы и внешние устройства.

Классификация операционных систем. Поддержка многопользовательского режима.

По числу одновременно работающих пользователей ОС делятся на:

  1. однопользовательские (MS-DOS, Windows 3.x, ранние версии OS/2);
  2. многопользовательские (UNIX, Windows NT).

Главным отличием многопользовательских систем от однопользовательских является наличие средств защиты информации каждого пользователя от несанкционированного доступа других пользователей.

Следует заметить, что не всякая многозадачная система является многопользовательской, и не всякая однопользовательская ОС является однозадачной.

Вытесняющая и не вытесняющая многозадачность

Среди множества существующих вариантов реализации многозадачности можно выделить две группы алгоритмов:

  1. не вытесняющая многозадачность (NetWare, Windows3.x);
  2. вытесняющая многозадачность (Windows NT, Unix).

Основным различием вытесняющего и не вытесняющего вариантов многозадачности является степень централизации механизма планирования процессов. В случае не вытесняющей многозадачности механизм планирования процессов целиком сосредоточен в операционной системе, а в случае вытесняющей многозадачности он распределен между системой и прикладными программами.

При не вытесняющей многозадачности активный процесс выполняется до тех пор, пока он сам, по собственной инициативе, не отдаст управление операционной системе для того, чтобы та выбрала из очереди другой готовый к выполнению процесс.

При вытесняющей многозадачности решение о переключении процессора с одного процесса на другой принимается операционной системой, а не самим активным процессом.

Поддержка многонитевости

Важным свойством операционных систем является возможность распараллеливания вычислений в рамках одной задачи.

Многонитевая ОС разделяет время процессора не между задачами, а между их отдельными ветвями (нитями).

Многопроцессорная обработка

В наши дни становится общепринятым введение в ОС функций поддержки многопроцессорной обработки данных.

Такие функции имеются в ОС:

  • Solaris 2.x фирмы Sun,
  • Open Server 3.x компании Santa Crus Operations,
  • FreeBSD (эти три операционные системы являются различными реализациями ОС Unix),
  • OS/2 фирмы IBM,
  • Windows NT фирмы Microsoft

Многопроцессорные ОС могут классифицироваться по способу организации вычислительного процесса в системе с многопроцессорной архитектурой:

Асимметричная операционная система целиком выполняется только на одном из процессоров системы, распределяя прикладные задачи по остальным процессорам.

Симметричная операционная система полностью децентрализована и использует весь пул процессоров, разделяя их между системными и прикладными задачами.

2. Классификация операционных систем Особенности аппаратных платформ

На свойства операционной системы непосредственное влияние оказывают аппаратные средства, на которые она ориентирована. По типу аппаратуры различают ОС:

  • персональных компьютеров,
  • мини-компьютеров,
  • мейнфреймов,
  • кластеров и сетей ЭВМ

Среди перечисленных типов компьютеров могут встречаться как однопроцессорные варианты, так и многопроцессорные.

В любом случае специфика аппаратных средств, как правило, отражается на специфике операционных систем.

Очевидно, что ОС большой машины является более сложной и функциональной, чем ОС персонального компьютера. Так в ОС больших машин функции по планированию потока выполняемых задач реализуются путем использования сложных приоритетных дисциплин и требуют большей вычислительной мощности, чем в ОС персональных компьютеров.

Аналогично обстоит дело и с другими функциями

Сетевая операционная система

windows

Многопроцессорные системы требуют от операционной системы особой организации, с помощью которой сама ОС, а также поддерживаемые этой ОС приложения могли бы выполняться параллельно отдельными процессорами системы.

Параллельная работа отдельных частей ОС создает дополнительные проблемы для разработчиков ОС, так как в этом случае гораздо сложнее обеспечить согласованный доступ отдельных процессов к общим системным таблицам, исключить нежелательные последствия асинхронного выполнения работ.

Операционная система кластеров

Другие требования предъявляются к операционным системам кластеров.

Наряду со специальной аппаратурой для функционирования кластерных систем необходима и программная поддержка со стороны ОС, которая сводится в основном к синхронизации доступа к разделяемым ресурсам, обнаружению отказов и динамической реконфигурации системы.

Одной из первых разработок в области кластерных технологий были решения компании Digital Equipment Corporation на базе компьютеров VAX. Недавно этой компанией заключено соглашение с корпорацией Microsoft о разработке кластерной технологии, использующей Windows NT. Несколько компаний предлагают кластеры на основе Unix-машин.

Мобильные операционные системы

Наряду с ОС, ориентированными на совершенно определенный тип аппаратной платформы, существуют операционные системы, специально разработанные таким образом, чтобы они могли быть легко перенесены с компьютера одного типа на компьютер другого типа, так называемые мобильные ОС.

Наиболее ярким примером такой ОС является популярная система Unix.

В этих системах аппаратно-зависимые места тщательно локализованы, так что при переносе системы на новую платформу переписываются только они. Средством, облегчающем перенос остальной части ОС, является написание ее на машинно-независимом языке, например, на языке Си, который и был разработан для программирования операционных систем

3. Классификация операционных систем Особенности областей использования ОС

Многозадачные ОС подразделяются на три типа в соответствии с использованными при их разработке критериями эффективности:

  • системы пакетной обработки (например, OC EC),
  • системы разделения времени (Unix, VMS),
  • системы реального времени (QNX, RT/11).
Системы пакетной обработки

Системы пакетной обработки предназначались для решения задач в основном вычислительного характера, не требующих быстрого получения результатов.

Главной целью и критерием эффективности систем пакетной обработки является максимальная пропускная способность, то есть решение максимального числа задач в единицу времени. Для достижения этой цели в системах пакетной обработки используются следующая схема функционирования:

  • в начале работы формируется пакет заданий, каждое задание содержит требование к системным ресурсам;
  • из этого пакета заданий формируется мультипрограммная смесь, то есть множество одновременно выполняемых задач.

В системах пакетной обработки переключение процессора с выполнения одной задачи на выполнение другой происходит только в случае, если активная задача сама отказывается от процессора, например, из-за необходимости выполнить операцию ввода-вывода. Поэтому одна задача может надолго занять процессор, что делает невозможным выполнение интерактивных задач. Таким образом, взаимодействие пользователя с вычислительной машиной, на которой установлена система пакетной обработки, сводится к тому, что он приносит задание, отдает его диспетчеру оператору, а в конце дня после выполнения всего пакета заданий получает результат. Очевидно, что такой порядок снижает эффективность работы пользователя.

Системы разделения времени

Критерием эффективности систем разделения времени является не максимальная пропускная способность, а удобство и эффективность работы пользователя.

Системы реального времени

Системы реального времени применяются для управления различными техническими объектами (станок, спутник, научная экспериментальная установка) или технологическими процессами (гальваническая линия, доменный процесс и т.п.). Во всех этих случаях существует предельно допустимое время, за которое должна быть выполнена та или иная программа, управляющая объектом, в противном случае может произойти авария: спутник выйдет из зоны видимости, экспериментальные данные, поступающие с датчиков, будут потеряны, толщина гальванического покрытия не будет соответствовать норме.

4. Классификация операционных систем Особенности методов построения ОС

В руководстве по работе с операционной системой часто указываются особенности ее структурной организации и основные концепции, положенные в ее основу.

К таким базовым концепциям относится способ построения ядра системы: монолитное ядро или микроядро.

Большинство ОС использует монолитное ядро , которое компонуется как одна программа, работающая в привилегированном режиме и использующая быстрые переходы с одной процедуры на другую, не требующие переключения из привилегированного режима в пользовательский режим и наоборот.

Монолитное ядро

микроядро

Построение ОС на базе объектно-ориентированного подхода дает возможность использовать все достоинства этого метода (хорошо зарекомендовавшие себя на уровне приложений) внутри операционной системы, а именно:

  • аккумуляцию удачных решений в форме стандартных объектов;
  • возможность создания новых объектов на базе имеющихся с помощью механизма наследования;
  • хорошую защиту данных за счет их инкапсуляции во внутренние структуры объекта, что делает данные недоступными для несанкционированного использования извне;
  • структурированность системы, состоящей из набора хорошо определенных объектов.

Наличие нескольких прикладных сред дает возможность в рамках одной ОС одновременно выполнять приложения, разработанные для нескольких ОС. Многие современные операционные системы поддерживают одновременно прикладные среды MS-DOS, Windows, Unix, OS/2 или хотя бы некоторого подмножества из этого популярного набора. Концепция множественных прикладных сред наиболее просто реализуется в ОС на базе микроядра, над которым работают различные серверы, часть которых реализуют прикладную среду той или иной операционной системы.

Распределенная организация операционной системы позволяет упростить работу пользователей и программистов в сетевых средах. В распределенной ОС реализованы механизмы, которые дают возможность пользователю представлять и воспринимать сеть в виде традиционного однопроцессорного компьютера.

Существует несколько схем классификации операционных систем . Ниже приведена классификация по некоторым признакам с точки зрения пользователя.

Реализация многозадачности

По числу одновременно выполняемых задач операционные системы можно разделить на два класса:

  • многозадачные (Unix, OS/2, Windows);
  • однозадачные (например, MS-DOS).

Многозадачная ОС , решая проблемы распределения ресурсов и конкуренции, полностью реализует мультипрограммный режим в соответствии с требованиями раздела "Основные понятия, концепции ОС ".

Многозадачный режим , который воплощает в себе идею разделения времени, называется вытесняющим ( preemptive ). Каждой программе выделяется квант процессорного времени, по истечении которого управление передается другой программе. Говорят, что первая программа будет вытеснена. В вытесняющем режиме работают пользовательские программы большинства коммерческих ОС .

В некоторых ОС (Windows 3.11, например) пользовательская программа может монополизировать процессор , то есть работать в невытесняющем режиме. Как правило, в большинстве систем не подлежит вытеснению код собственно ОС . Ответственные программы, в частности задачи реального времени, также не вытесняются. Более подробно об этом рассказано в лекции, посвященной планированию работы процессора .

По приведенным примерам можно судить о приблизительности классификации. Так, в ОС MS-DOS можно организовать запуск дочерней задачи и наличие в памяти двух и более задач одновременно. Однако эта ОС традиционно считается однозадачной, главным образом из-за отсутствия защитных механизмов и коммуникационных возможностей.

Поддержка многопользовательского режима

По числу одновременно работающих пользователей ОС можно разделить на:

  • однопользовательские (MS-DOS, Windows 3.x);
  • многопользовательские (Windows NT, Unix).

Наиболее существенное отличие между этими ОС заключается в наличии у многопользовательских систем механизмов защиты персональных данных каждого пользователя.

Многопроцессорная обработка

Вплоть до недавнего времени вычислительные системы имели один центральный процессор . В результате требований к повышению производительности появились многопроцессорные системы , состоящие из двух и более процессоров общего назначения, осуществляющих параллельное выполнение команд. Поддержка мультипроцессирования является важным свойством ОС и приводит к усложнению всех алгоритмов управления ресурсами. Многопроцессорная обработка реализована в таких ОС , как Linux, Solaris, Windows NT, и ряде других.

Многопроцессорные ОС разделяют на симметричные и асимметричные. В симметричных ОС на каждом процессоре функционирует одно и то же ядро, и задача может быть выполнена на любом процессоре , то есть обработка полностью децентрализована . При этом каждому из процессоров доступна вся память.

В асимметричных ОС процессоры неравноправны. Обычно существует главный процессор (master) и подчиненные (slave), загрузку и характер работы которых определяет главный процессор .

Системы реального времени

В разряд многозадачных ОС , наряду с пакетными системами и системами разделения времени , включаются также системы реального времени , не упоминавшиеся до сих пор.

Они используются для управления различными техническими объектами или технологическими процессами. Такие системы характеризуются предельно допустимым временем реакции на внешнее событие, в течение которого должна быть выполнена программа, управляющая объектом. Система должна обрабатывать поступающие данные быстрее, чем они могут поступать, причем от нескольких источников одновременно.

Столь жесткие ограничения сказываются на архитектуре систем реального времени , например, в них может отсутствовать виртуальная память, поддержка которой дает непредсказуемые задержки в выполнении программ. (См. также разделы, связанные с планированием процессов и реализацией виртуальной памяти.)

Приведенная классификация ОС не является исчерпывающей. Более подробно особенности применения современных ОС рассмотрены в [Олифер, 2001].

Заключение

Мы рассмотрели различные взгляды на то, что такое операционная система ; изучили историю развития операционных систем ; выяснили, какие функции обычно выполняют операционные системы ; наконец, разобрались в том, какие существуют подходы к построению операционных систем . Следующую лекцию мы посвятим выяснению понятия "процесс" и вопросам планирования процессов.

Читайте также: