Уровни параллелизма.
Как мы знаем, первые компьютеры удовлетворяли почти всем принципам Фон Неймана. В этих компьютерах поток последовательно выполняемых в центральном процессоре команд обрабатывал поток данных. ЭВМ такой простой архитектуры носят в литературе сокращённое название ОКОД (Один поток Команд обрабатывает Один поток Данных – английское сокращение SISD: Single Instruction Single Data). В настоящее время компьютеры, однако, нарушают почти все принципы Фон Неймана. Дело в том, что вычислительная мощность современных компьютеров базируется как на скорости работы всех узлов ЭВМ, так и, в значительной степени, на параллельной обработке данных. В заключение нашего краткого изучения архитектуры современных ЭВМ рассмотрим классификацию способов параллельной обработки данных на компьютере.
· Параллельное выполнения программ может производиться на одном компьютере, если он имеет несколько центральных процессоров. Как правило, в этом случае компьютер имеет и несколько периферийных процессоров (каналов). Существуют ЭВМ, у которых могут быть от нескольких десятков до нескольких сотен и даже тысяч центральных процессоров. В таких компьютерах много потоков команд одновременно обрабатывают много потоков данных, в научной литературе это обозначается сокращением МКМД (или по-английски MIMD).
· Параллельные процессы в рамках одной программы. Программа пользователя может породить несколько параллельных процессов обработки данных, каждый такой процесс для операционой системы является самостоятельной единицей работы. Процессы одной задачи могут псевдопараллельно выполняться в мультипрограммном режиме точно так же, как и задачи независимых пользователей.
В качестве примера рассмотрим случай, когда программисту необходимо вычислить сумму значений двух функций F(x)+G(x), причём каждая из этих функций для своего вычисления требует больших затрат процессорного времени и производит много обменов данными с внешними запоминающими устройствами. В этом случае программисту выгодно распараллелить алгоритм решения задачи и породить в своей программе два параллельных вычислительных процесса, каждому из которых поручить вычисления одной из этих функций. Можно понять, что в этом случае вся программа будет посчитана за меньшее физическое время, чем при использовании одного вычислительного процесса. Действительно пока один процесс будет производить обмен данными с медленными внешними устройствами, другой процесс может продолжать выполняться на центральном процессоре, а в случае с одним процессом вся программа была бы вынуждена ждать окончания обмена с внешним устройством. Стоит заметить, что скорость счёта программы с несколькими параллельными процессами ещё больше возрастёт на компьютерах, у которых более одного центрального процессора.
Подробно параллельные процессы Вы будете изучать в следующем семестре.
· Параллельное выполнение нескольких команд одной программы производится конвейером центрального процессора. В мощных ЭВМ центральный процессор может содержать несколько конвейеров. Например, один из конвейеров выполняет команды целочисленной арифметики, другой предназначен для обработки вещественных чисел, а третий – для всех остальных команд.
· Параллельная обработка данных в программе производится на так называемых векторных ЭВМ. У таких ЭВМ наряду с обычными (скалярными) регистрами есть и векторные регистры, которые могут хранить и выполнять операции над векторами целых или вещественных чисел. Пусть, например, у такой ЭВМ есть регистры axv и bxv, каждый из которых может хранить вектор из 64 чисел, тогда команда векторного сложения addv axv,bxv будет производить параллельное покомпонентное сложение всех элементов таких векторов по схеме axv[i]:=axv[i]+bxv[i]. Можно сказать, что на векторных ЭВМ один поток (векторных) команд обрабатывает много потоков данных (поток векторных данных). Отсюда понятно сокращённое название ЭВМ такой архитектуры – ОКМД (по-английски SIMD).[92]
Параллельная обработка команд и данных позволяет значительно увеличить производительность компьютера. Необходимо сказать, что в современных компьютерах обычно реализуется сразу несколько из рассмотренных выше уровней параллелизма. Познакомится с историей развития параллельной обработки данных можно, например, по книге [15]. Заметим, однако, что, несмотря на непрерывный рост мощности компьютеров, постоянно появляются всё новые задачи, для счёта которых необходимы ещё более мощные ЭВМ. Таким образом, к сожалению, рост сложности задач опережает рост производительности компьютеров.
[1] В области компьютеров и программного обеспечения такие уровни используются, например, при описании структуры баз данных, где описания данных (схемы данных) могут рассматриваться на внешнем, концептуальном и внутреннем уровнях [12].
[2] Разумеется, время чтения из ячейки памяти может не совпадать с временем записи в неё.
[3] Если только такое участие не предусмотрено в самой программе, например, при вводе данных с клавиатуры. Пример устройства, которое может выполнять команды, но не в автоматическом режиме – обычный (непрограммируемый) калькулятор.
[4] Тип real Турбо-Паскаля не подходит, потому что имеет длину 48 бит, а не 32, как нам нужно.
[5] В настоящее время существуют алфавиты, содержащие большое количество (порядка 32000) символов, для их представления, естественно, используются длинные беззнаковые целые числа.
[6] При этом правильно учитывается знак числа, например, (-8)*(-e)= +e
[7] Эти имена (как и имена всех остальных регистров нашей ЭВМ) являются служебными в языке Ассемблера. Напомним, что служебные имена нельзя использовать ни в каком другом смысле.
[8] В некоторых ассемблерах допускается эквивалентная запись выражения A[M1][M2] в виде A[M1+M2] и даже в виде [A+M1+M2].
[9] Это сделано специально, так как схемы центрального процессора, выполняющие инсремент и декремент операнда используются и при выполнении некоторых других команд, которые не должны менять этот флаг.
[10] Как мы узнаем позже, на самом деле производится перевод не на язык машины, а на специальный промежуточный объектный язык.
[11] Для особо любознательных студентов: для перекрывающихся сегментов можно ухитриться получить доступ к ячейкам одного сегмента через сегментный регистр, указывающий на другой сегмент. Мы, естественно, такими фокусами заниматься не будем.
[12] Исключением, например, является директива include, на место которой подставляется некоторый текстовый файл. Этот файл может содержать описание целого сегмента или же наборы фрагментов программ (так называемые макроопределения). С примером использования этой директивы мы вскоре познакомимся.
[13] Точнее, в машинном языке есть только операции обмена байтами между центральным процессором и периферийными устройствами компьютера, с этими операциями мы познакомимся позже.
[14] Можно дать загрузчику явное указание на размещение конкретного сегмента с заданного адреса оперативной памяти (мы изучим это позднее в нашем курсе), но это редко когда нужно программисту. Наоборот, лучше писать программу, которая будет правильно работать при любом размещении её сегментов в оперативной памяти.
[15] При достижении в программе конца оперативной памяти (или конца сегмента при сегментной организации памяти) обычно выполняется команда, расположенная в начале памяти или в начале этого сегмента.
[16] В принципе переход возможен и при изменении значения только одного регистра CS, однако в практике программирования такие переходы практически не имеют смысла и не реализуются.
[17] Необходимо учитывать, что в момент выполнения команды перехода счётчик адреса IP уже указывает на следующую команду, что, конечно, существенно при вычислении величины смещение. Но, так как эту работу выполняет программа Ассемблера, мы на эту особенность не будем обращать внимания.
[18] Например, при написании встроенных программ для управления различными устройствами (стиральными машинами, видеомагнитофонами и т.д.), либо программ дла автоматических космических аппаратов, где память относительно небольшого объёма, т.к. особая, способная выдерживать космическое излучение.
[19] Флаг чётности равен единице, если в восьми младших битах результата содержится чётное число двоичных единиц. Мы не будем работать с этим флагом.
[20] Если не принимать во внимание то, что константа в Паскале имеет тип, это позволяет контролировать её использование, а в Ассемблере это просто указание о текстовой подстановке вместо имени операнда директивы эквивалентности.
[21] Вообще говоря, это же правило можно записать и как "первый пришёл – последний вышел" (английское сокращение FILO). В литературе встречаются оба этих правила и их сокращения.
[22] Иногда в наших примерах мы, следуя учебнику [5], называли так же и сам сегмент стека. Некоторые компиляторы с Ассемблера (например, MASM-4.0) допускают это, если по контексту могут определить, что это именно имя пользователя, а не служебное слово. Другие компиляторы (например, Турбо-Ассемблер) подходят к этому вопросу более строго и не допускают использование служебных слов в качестве имён пользователя. Все служебные слова Ассемблера мы выделяем жирным шрифтом.
[23] Отметим и другие полезные имена констант в языке Ассемблера: byte=1,word=2,dword=4,abs=0.
[24] Под основной программой мы имеем в виду то место нашей программы, где вызывается процедура, т.е. возможен и случай, когда одна процедура вызывает другую (в том числе рекурсивно саму себя).
[25] В языке Турбо-Паскаль для этой цели можно использовать оператор присваивания bx:=@X[1]
[26] Практически все современные компьютеры имеют аппаратно реализованный стек, если же это не так, то в стандартных соглашениях о связях для таких ЭВМ устанавливаются какие-нибудь другие способы передачи параметров, этот случай мы рассматривать не будем.
[27] Является ли адрес близким (т.е. смещением в сегменте данных) или же дальним (значение сегментного регистра и смещение) обычно специфицируется при написании процедуры на языке высокого уровня. Ясно, что, скорее всего во внешнюю процедуру будут передаваться дальние адреса.
[28] Обратный порядок позволяет более легко реализовывать процедуры и функции с переменным числом параметров, но он менее эффективен, чем прямой, так как труднее удалить из стека фактические параметры после окончания процедуры. В связи с этим, например, в языке С при описании внешней процедуры программист может явно указывать порядок записи фактических параметров в стек.
[29] При обратном порядке записи фактических параметров в стек (как в языке С) удаление из стека параметров обычно делает не процедура, а основная программа, т.к. это легче реализовать для переменного числа параметров. Плохо в этом случае то, что такое удаление приходится выполнять в каждой точке возврата из процедуры, что может существенно увеличить размер кода программы.
[30] На языке Турбо-Паскаль так написать нельзя, массивы A и B не поместятся в один сегмент данных, а размещать статические переменные в разных сегментах Турбо-Паскаль не умеет.
[31] Даже если это деление на ноль, всё равно можно считать, что центральный процессор закончил выполнение этой команды, хотя значение частного при этом, конечно, не определено. Для особо любознательных студентов можно также сказать, что некоторые старые ЭВМ могли начать реакцию на прерывание и без завершения текущей команды (например, если это "длинная" команда, выполнение которой занимает много времени, в этом случае выполнение такой команды могло быть продолжено с прерванного места).
[32] Хотя некоторые программы могут выполняеться полностью в режиме закрытых прерываний, но не надо забывать, что существуют прерывания, которые нельзя замаскировать.
[33] Точнее контекстом процесса, о процессах Вы узнаете в курсе "Системное программное обеспечение".
[34] В частности, сигналом с таким же номером N, при этом произойдёт повторный вход в начало этой же самой процедуры-обработчика. Те программы, которые допускают такой повторный вход в своё начало (не путать это с рекурсивным вызовом!), называются повторно-входимыми или реентерабельными. Программы обработки прерываний для младших моделей нашего семейства могли и не быть реентерабельными, что порождало известные проблемы, которые мы здесь обсуждать не будем.
[35] Если прерванных (готовых к продолжению своего счёта) программ больше одной, то часто может понадобиться произвести возврат не в последнюю прерванную программу, а в какую-нибудь другую из этих программ. Поэтому после окончания своей работы процедура-обработчик прерывания передаёт управление специальной системной программе – диспетчеру, и уже программа-диспетчер определяет, которая из прерванных программ должна быть продолжена.
[36] Точнее, лишним будет только использование адресуемого регистра центрального процессора (ax,bx и т.д.). Как мы знаем, двухадресные команды формата память-память КОП оp1,op2 обязательно требует для своего выполнения использования служебного регистра центрального процессора, (мы обозначали этот регистр R1) и выполняются по схеме:
R1:=op1; R1:=R1 КОП op2; op1:=R1.
[37] Такое значительное уменьшение сложности алгоритма верно только для младших моделей нашего семейства. В старших моделях появилась специальная быстродействующая область памяти – кэш, в которую автоматически помещаются, в частности, последние выполняемые команды. Таким образом, весь наш первоначальный цикл пересылки из 5 команд будет находиться в этой кэш-памяти, скорость чтения из которой примерно на порядок больше скорости чтения из оперативной памяти. Другими словами, обращения в оперативную память за командами при выполнении цикла пересылки массива в старших моделях тоже производиться не будет, и сложность алгоритма также приближается к 2*N обменов. Более подробно с памятью типа кэш Вы познакомитесь в курсе "Системное программное обеспечение".
[38] Для двух команд сдвига в этом наборе будет 9 или 17 бит, это мы далее отметим особо.
[39] Для любознательных отметим, что для описания работы логических команд более подходит оператор цикла параллельного Фортрана, например: for all i do op1[i]:=op1[i]<>op2[i], который предписывает выполнить тело цикла одновременно (параллельно) для всех значений параметра цикла i.
[40] В старших моделях нашего семейства у команд сдвига допускается также второй операнд формата i8. Мы в своих примерах этим форматом пользоваться не будем.
[41] Из этого правила совсем немного исключений, с большинством из них мы познакомимся при изучении макросредств языка Ассемблера.
[42] Точнее на объектный язык, о чём мы будем говорить далее.
[43] Установление связей может быть отложено на этап счёта программы, о чём вы будем говорить позже при изучении динамического загрузчика.
[44] Это верно и для случая, когда один модуль использует константу, определённую в другом модуле, так как константа – это тоже целое число (непосредственное значение в поле адреса i8 или i16).
[45] В некоторых языках имена по умолчанию считаются доступными из других модулей, если они описаны или объявлены в определённой части модуля. Например, в модуле на языке С общедоступны все имена, описанные вне функций, если про них явно не сказано, что это локальные имена модуля.
[46] Иногда говорят, что имя A объявлено в сегменте Data (правда термин "объявить имя" используется в основном в языках высокого уровня). Объявление имени в некотором сегменте, в отличие от описания этого имени, не требует выделения для переменной A памяти в сегменте. Для Ассемблера это является указанием (директивой) о том, что во время счёта программы данная переменная будет находится в памяти именно этого сегмента.
[47] Вообще говоря, все имена, кроме внешних имён и имён входных точек, могут заменяться в объектном модуле номерами. Например, уже на важно, какие именно имена давал программист сегментам в своей программе, эта информация больше никому не понадобится.
[48] Если объектных модулей очень много, то существует более компактный способ задать их, не перечисляя их все в строке вызова редактора внешних связей.
[49] Вообще говоря, склеиваемые сегменты должны ещё принадлежать к одному и тому же классу сегментов. В наших примерах это выполняется, для более полного изучения понятия класса сегмента необходимо обратиться, например, к учебнику [5].
[50] Заметим, что одноимённые сегменты с параметром public могут встречаться и внутри одного модуля. В этом случае такие сегменты тоже склеиваются, но эту работу, как правило, проводит сама программа Ассемблера.
[51] Стиль программирования с общими (накладываемыми друг на друга) сегментами данных широко используется, например, в языке Фортран, при этом часто случаются ошибки, вызванные плохим семантическим согласованием общих сегментов данных.
[52] В загрузочном модуле могут не храниться "пустые" сегменты данных, которые состоят только из директив резервирования памяти без начальных значений. Для сегментов данных, в которых есть области памяти, как с начальными значениями, так и без начальных значений, лучше сначала описывать области памяти с начальными значениями. Это даёт возможность помещать такой сегмент данных в загрузочный модуль в "урезанном" виде, все области данных без начальных значений в файл не записываются, что позволяет уменьшить размер файла загрузочного модуля. Разумеется, в паспорте загрузочного модуля хранится полная информация обо всех его сегментах (в частности, об их длине).
[53] Максимальный объём дополнительной памяти указывается из соображений безопасности, чтобы из-за ошибок в программе она не стала запрашивать в цикле всё новые и новые блоки памяти, что может сильно помешать счёту других программ.
[54] Как мы уже упоминали, "пустые" сегменты, содержащие только переменные без начальных значений, в загрузочном модуле обычно не храняться, такие сегменты просто размещаются на свободных местах памяти и, естественно, области памяти в них не будут иметь конкретных начальных значений.
[55] Так как эти действия требуют больше одной команды, то их надо проводить в режиме с закрытыми прерываниями, чтобы не использовать не полностью подготовленный к работе стек при возникновении прерывания (т.е. эта часть загрузчика является уже знакомой нам критической секцией).
[56] Виртуальная память позволяет использовать в программе диапазон адресов памяти, превышающий физический объём памяти компьютера. Например, при физической памяти 220 байт (как в нашей младшей модели) можно использовать адресное пространство в 224 байт. С виртуальной памятью Вы познакомитесь в следующем семестре в курсе "Системное программное обеспечение".
[57] Есть и другая причина широкого распространения схемы счёта сдинамическим связыванием и динамической загрузкой модулей, мы рассмотрим эту причину при изучении работы ЭВМ в так называемом мультипрограммном режиме.
[58] В современных технологиях программирования проверка того, что существуют все модули, вызов которых возможен при счёте программы, может оказаться весьма трудоёмкой операцией. Дело в том, что эти модули могут, в принципе, находится где угодно, например, в сетевой (удалённой) библиотеке объектных модулей на другом конце Земли.
[59] Точнее, как мы уже говорили, ищется объектный модуль, в котором расположена эта процедура.
[60] Эта схема может быть неприемлема, например, для так называемых программ реального времени, которые предназначены для управления быстрыми внешними устройствами (ракетой, химическим или ядерным реактором и т.д.).
[61] Как мы узнаем позже, на однопроцессорной ЭВМ в каждый момент времени компилируется только одна программа, но по сигналам прерывания от внутренних часов компьютера может производиться быстрое переключение с одной программы на другую, так что создаётся впечатление, что компилируются (хотя и более медленно) сразу несколько программ.
[62] Макросредства могут использоваться также и в формальных языках, не являющихся языками программирования, но этот вопрос далеко выходит за рамки нашего курса.
[63] В наших программах мы выделяли имена макрокоманд жирным шрифтом (finish,inint и т.д.), хотя это, конечно, не совсем правильно, так как это не служебные слова Макроасемблера.
[64] Если у макрокоманды есть метка, то считается, что эта метка задаёт отдельное предложение Ассемблера, состоящее только из данной метки. Другими словами, макрокоманда с меткой:
<метка>[:]<имя макрокоманды> [<список фактических параметров>]
эквивалентна двум таким предложения Ассемблера:
<метка>[:]
<имя макрокоманды> [<список фактических параметров>]
[65] Это несколько упрощённое описание действий Макропроцессора при передаче параметров, позже мы сделаем существенные уточнения.
[66] Вообще говоря, на самом деле Макропроцессор и Ассемблер обрабатывают программу одновременно, предложение за предложением. Как мы вскоре узнаем, первыми каждое предложение обрабатывают специальные программы Ассемблера, которые называются лексическим и синтаксическим анализаторами, а затем, если нужно, это предложение обрабатывает Макропроцессор. Однако конечный этап компиляции – генерация объектного модуля – выполняется Ассемблером уже после полного завершения работы Макропроцессора.
[67] Точнее, директива exitm производится выход вниз за ближайшую директиву endm, которая, как мы вскоре узнает, может задавать конец не только макроопределения, но и макроциклов. Таким образом, exitm прекращает обработку той части макроопределения, которая ограничена ближайшей вниз директивой endm.
[68] Вообще говоря, во время компиляции стандартный вывод stdout должен быть связан с файлом листинга, а стандартный вывод об ошибках stderr – с экраном дисплея. Однако некоторые Ассемблеры (и среди них, к сожалению, MASM-4.0) могут во время компиляции связывать стандартный вывод stdout тоже с экраном, а вывод в листинг производить путём указания имени конкретного файла. В этом случае диагностика, заданная директивой %out в макрорасширение (и в листинг) не попадёт, а будет дважды выведена на экран.
[69] Заметим, что в языках высокого уровня обычно есть далеко не все из рассматриваемых нами макросредств.
[70] Для простоты наше макроопределение никогда не задаёт второй параметр макрокоманды outint – ширину поля для вывода целого числа.
[71] В стандарте Паскаля можно попытаться сделать элементы массива записями с вариантами, в Турбо-Паскале – использовать так называемые безтиповые массивы. Однако во всех этих случаях, даже если не принимать во внимание отсутствие контроля и понижение надёжности программы, нам придётся передавать в функцию дополнительный параметр, задающий тип элемента массива, а внутри функции будет по-существу находиться оператор case, разветвляющий вычисление по разным типам данных. Не спасают здесь положение и объектно-ориентированные языки, всё равно придётся реализовать в программе несколько функций с одинаковым именем, компилятор лишь автоматически выберет одну из них, соответствующую типу элементов массива, переданного как фактический параметр.
[72] Тот факт, что короткие алгоритмы иногда выгоднее реализовывать не в виде процедур и функций, а в виде макроопределений, нашёл отражение и при разработке языков высокого уровня. Так, в некоторых языках высокого уровня, существуют так называемые встраиваемые (inline) процедуры и функции, вызов которых во многом производится по тем же правилам, что и вызов макроопределений.
[73] Термин транслятор обозначает программу-переводчика с одного языка на другой. Трансляторы делятся на компиляторы, которые переводят программу целиком, и интерпретаторы, которые выполняют построчный перевод и исполнение каждой переведённой строки программы. Хорошим аналогом является писменный (всего текста) и устный (синхронный, по одному предложению) перевод с иностранного языка.
[74] Как вы узнаете из курса "Системное программное обеспечения" выдача листинга и аварийных диагностик производится на разные устройства – так называемое стандартное устройство вывода (stdout) и стандартное устройство для выдачи сообщений об ошибках (stderr).
[75] В отличие от Паскаля, в Ассемблере нет стандартных имён (напомним, что стандартное имя имело заранее определённый смысл, но эти имена можно было переопределить).
[76] Здесь надо сказать, что компилятор не предполагает глубокого знание программистом теории компиляции, поэтому в дистинге такие ошибки называются общим термином "синтаксические ошибки", хотя, как мы узнаем немного позже, "настоящие" синтаксические ошибки определяются другой частью компилятора – синтаксическим анализатором.
[77] Исключением из этого правила, как мы знаем, являются имена сегментов и имена процедур, которые должны встретиться в поле метки два раза.
[78] Эти программы могут присутствовать в оперативной памяти не целиком. Во-первых, они могут использовать схему динамической загрузки, и, во-вторых, работать на так называемой виртуальной памяти, при этом некоторые части программы могут временно отсутствовать в оперативной памяти.
[79] На ЭВМ первых поколений пользователям разрешалось писать свои собственные процедуры-обработчики прерываний, однако в операционных системах современных ЭВМ это, как правило, запрещено. Причина такого запрета будет понятна из нашего дальнейшего изложения мультипрограммного режима работы ЭВМ.
[80] Даже если не принимать во внимание "вредных" программистов, которые специально захотят испортить или незаконно прочитать данные других программ, всегда существуют вероятность таких действий из-за ошибок в программах даже у "добропорядочных" программистов.
[81] В архитектуре нашего компьютера регистр режима работы содержит два разряда и может принимать значения 0,1,2 и 3. Практически всегда, однако, используются только два из этих четырёх значений (0 и 3).
[82] Способы задания таких полномочий Вы будете изучать в следующем семестре на примере операционной системы Unix.
[83] Конечно, существуют привилегированные команды для работы с кэшем как с единым целым, это, например, команда очистки кэша от всех команд и данных.
[84] Как видно из этого алгоритма работы кэша, от весьма "болезненно" реагирует на прерывания, так как при этом производится переключение на другую программу, и данные в кэше необходимо полностью сменить.
[85] За одно обращение из памяти теперь читается не одна команда, а в среднем две последовательные команды, поэтому можно считать, что среднее время выполнения команды будет ещё меньше: 1+2+2=5 нс.
[86] Такие компиляторы называются оптимизирующими компиляторами, оптимизация на машинном языке выполняется обычно на одном или нескольких дополнительных проходах программы перед получением объектного модуля.
[87] На супер-ЭВМ для этих целей обработку большинства прерываний обычно поручают одному из каналов ввода/вывода (периферийных процессоров), что позволяет не прерывать работу конвейера центрального процессора. Архитектуру ЭВМ с каналами ввода/вывода мы будем изучать далее.
[88] Это яркий пример того, как макросредства повышают уровень языка: макрокоманда вывода символа оказываеся для Петрова по внешнему виду (если отвечься от деталей синтаксиса), очень похожа на соответствующие операторы языков высокого уровня.
[89] Предполагается, что компьютер работает в простейшем (как говорят, незащищённом) режиме.
[90] Мы рассматриваем, естественно, работу дисплея только в стандартном текстовом режиме.
[91] Естественно, что немедленное продолжение выполнения программы пользователя возможно только в том случае, если ей не требуется сразу обрабатывать данные, которые должен предоставить канал. Например, если программа обратиласть к каналу для чтения массива с диска в свою оперативную память, и пожелает тут же начать суммировать элементы этого массива, то такая программа будет переведена в состояние ожидания, пока канал не закончит чтения заказанного массива в память. Аналогично программа будет переведена в состояние ожидания, если она обратиласть к каналу для записи некоторого своего массива из оперативной памяти на диск, и пожелала тут же начать присваивать элементам этого массива новые значения. Эти примеры, в частности, показывают, насколько усложняются большинство программ операционой системы в архитектуре с каналами ввода/вывода.
[92] Для полноты классификации можно упомянуть и архитектуру МКОД (MISD), при этом один поток данных обрабатывается многими потоками команд. В качестве примера можно привести специализированную ЭВМ, управляющую движением самолётов над аэропортом. В этой ЭВМ один поток данных от аэродромного радиолокатора обрабатывается многими параллельно работающими процессорами, каждый из которых следит за безопасностью полёта одного закреплённого за ним самолёта, давая ему при необходимости команды на изменение курса, чтобы предотвратить столкновение с другими самолётами. С другой стороны, однако, можно считать, что каждый процессор обрабатывает свою копию общих данных и рассматривать это как частный случай архитектуры МКМД.
Дата добавления: 2015-10-05; просмотров: 904;