Курсовая Особенности реализации многозадачности ОС Windows
Работа добавлена на сайт bukvasha.net: 2015-10-25Поможем написать учебную работу
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
от 25%
договор
Федеральное агентство по образованию Российской Федерации
ГОУ ВПО «Шадринский государственный педагогический институт»
Кафедра прикладной информатики
Курсовая работа
по предмету «Информатика»
на тему «Особенности реализации многозадачности ОС
Windows
».
Выполнила:
студентка факультета информатики
группа 486
Бологова А.И.
Преподаватель: Парфенов С.Ю.
г. Шадринск
2007
Содержание
Введение. 3
Глава I. Многозадачность и виды многозадачности. 5
1.1. Многозадачность и многопоточность. 5
1.2. Особенности реализации многозадачности в DOS. 6
1.3. Presentation Manager и последовательная очередь сообщений. 9
1.4. Многопоточная архитектура. 11
1.5. Преимущества Windows. 13
1.6. Объект Mutex. 19
Глава II. Особенности реализации многозадачности Windows 2003. 23
2.1. Реализация многозадачности в Windows 2003. 23
2.2. Управление квантованием в Windows 2003. 25
2.3. Управление приоритетами в Windows 2003. 27
2.4. Особенности многозадачности в среде Windows 2003. 29
Заключение. 34
Список используемой литературы.. 38
Введение
К моменту появления персональных компьютеров в мире существовало несколько технических решений позволяющих реализовать многозадачность на больших машинах. В бывшем СССР это были машины серии ЕС и болгарские ИЗОТ. Они теоретически позволяли подключать до 255 терминалов, где каждому терминалу выделялось некоторое количество ресурсов компьютера и процессорного времени. На практике нормальная работа такого комплекса обеспечивалась при наличии не более 25-30 терминалов, или меньше при сложных задачах [3 , c. 20].
Для персональных ЭВМ многозадачность не вводилась принципиально. Ведь исходя из названия PC – “Personal Computer” предполагалось, что работать будет один человек с одной текущей задачей. В качестве операционной системы была принята переработанная система CP/M под названием MS-DOS. Она так же не предусматривала многозадачности. Основная проблема разработки многозадачной операционной системы это не реентерабельность ее функций. То есть если один процесс запустил функцию чтения файла, то другой процесс не сможет не только обращаться к файлам, но и вообще вызвать другие ее функции. Для этого необходима поддержка на уровне процессора, которая была введена с разработкой линейки 286.
Для современных операционных систем и для различных систем программирования в современном мире поддержка разработки и реализация многозадачности стала необходимой. При этом на применяемые решения влияет значительное число факторов.
Конкретная реализация очень сильно зависит от того, какая вычислительная система и какие аспекты работы этой системы рассматриваются с точки зрения многозадачности. Так, например, в некоторых случаях эффективным способом реализации многозадачности может быть использование асинхронных операций ввода-вывода; в других случаях будет целесообразным использование механизмов передачи сообщений; очень часто применяется обмен данными через область совместно доступной памяти. Поэтому знакомство следует начать с основных сведений о вычислительных системах.
Современные операционные системы, как правило, поддерживают несколько различных механизмов многозадачности. Конкретный выбор в конкретной системе зачастую оказывает значительное влияние на правила разработки приложений. Поэтому следующим шагом должно быть знакомство с поддержкой многозадачности операционными системами. Мы рассмотрим в общих чертах реализацию многозадачности в Windows.
Однако, главным является не компьютер и не установленная на нем операционная система - всё это делается только для того, чтобы обеспечить эффективное выполнение приложений. Соответственно знакомство с многозадачностью должно завершиться обсуждением средств, которые операционная система предоставляет разработчикам приложений, и некоторым приемам разработки приложений.
Цель: Выявить особенности реализации многозадачности ОС Windows.
Задачи:
Охарактеризовать понятие многозадачности и многопоточности;
Выявить особенности архитектуры многопоточных программ;
Рассмотреть особенности реализации многозадачности и многопоточности в ОС Windows;
Определить понятие объекта Mutex;
Рассмотреть реализацию многозадачности в Windows 2003;
Показать управление квантованием и приоритетами в Windows 2003.
Глава I. Многозадачность и виды многозадачности
1.1. Многозадачность и многопоточность
Многозадачность (multitasking) – это способность операционной системы выполнять несколько программ одновременно. В основе этого принципа лежит использование операционной системой аппаратного таймера для выделения отрезков времени (time slices) для каждого из одновременно выполняемых процессов. Если эти отрезки времени достаточно малы, и машина не перегружена слишком большим числом программ, то пользователю кажется, что все эти программы выполняются параллельно.[9, c. 56]
Идея многозадачности не нова. Многозадачность реализуется на больших компьютерах типа мэйнфрэйм (mainframe), к которым подключены десятки, а иногда и сотни, терминалов. У каждого пользователя, сидящего за экраном такого терминала, создается впечатление, что он имеет эксклюзивный доступ ко всей машине. Кроме того, операционные системы мэйнфрэймов часто дают возможность пользователям перевести задачу в фоновый режим, где они выполняются в то время, как пользователь может работать с другой программой.
Для того, чтобы многозадачность стала реальностью на персональных компьютерах, потребовалось достаточно много времени. Но, кажется, сейчас мы приближаемся к эпохе использования многозадачности на ПК (PC). Как мы увидим вскоре, некоторые расширенные 16-разрядные версии Windows поддерживают многозадачность, а имеющиеся теперь в нашем распоряжении Windows NT и Windows 95 – 32-разрядные версии Windows, поддерживают кроме многозадачности еще и многопоточность (multithreading).
Многопоточность – это возможность программы самой быть многозадачной. Программа может быть разделена на отдельные потоки выполнения (threads), которые, как кажется, выполняются параллельно. На первый взгляд эта концепция может показаться едва ли полезной, но оказывается, что программы могут использовать многопоточность для выполнения протяженных во времени операций в фоновом режиме, не вынуждая пользователя надолго отрываться от машины. [4, c. 25]
1.2. Особенности реализации многозадачности в DOS
Микропроцессор Intel 8088, использовавшийся в первых ПК, не был специально разработан для реализации многозадачности. Частично проблема (как было показано в предыдущей главе) заключалась в недостатках управления памятью. В то время, как множество программ начинает и заканчивает свое выполнение, многозадачная операционная система должна осуществлять перемещение блоков памяти для объединения свободного пространства. На процессоре 8088 это было невозможно реализовать в стиле, прозрачном для приложений.
Сама DOS не могла здесь чем-либо существенно помочь. Будучи разработанной таким образом, чтобы быть маленькой и не мешать приложениям, DOS поддерживала, кроме загрузки программ и обеспечения им доступа к файловой системе, еще не так много средств.
Тем не менее, творческие программисты, работавшие с DOS на заре ее появления, нашли путь преодоления этих препятствий, преимущественно при использовании резидентных (terminate-and-stay-resident, TSR) программ. Некоторые TSR-программы, такие как спулер печати, использовали прерывание аппаратного таймера для выполнения процесса в фоновом режиме. Другие, подобно всплывающим (popup) утилитам, таким как SideKick, могли выполнять одну из задач переключения – приостановку выполнения приложения на время работы утилиты. DOS также была усовершенствована для обеспечения поддержки резидентных программ.
Некоторые производители программного обеспечения пытались создать многозадачные оболочки или оболочки, использующие переключение между задачами, как надстройки над DOS (например, Quarterdeck's DeskView), но только одна из этих оболочек получила широкое распространение на рынке. Это, конечно. Windows.
Когда Microsoft выпустила на рынок Windows 1.0 в 1985 году, это было еще в большой степени искусственным решением, придуманным для преодоления ограничений MS DOS. В то время Windows работала в реальном режиме (real mode), но даже тогда она была способна перемещать блоки физической памяти (одно из необходимых условий многозадачности) и делала это, хотя и не очень прозрачно для приложений, но все-таки вполне удовлетворительно.
В графической оконной среде многозадачность приобретает гораздо больший смысл, чем в однопользовательской операционной системе, использующей командную строку. Например, в классической операционной системе UNIX, работающей с командной строкой, существует возможность запускать программы из командной строки так, чтобы они выполнялись в фоновом режиме. Однако, любой вывод на экран из программы должен быть переадресован в файл, иначе этот вывод смешается с текущим содержимым экрана.
Оконная оболочка позволяет нескольким программам выполняться совместно, разделяя один экран. Переключение вперед и назад становится тривиальным, существует возможность быстро передавать данные из одной программы в другую, например, разместить картинку, созданную в программе рисования, в текстовом файле, образованном с помощью текстового процессора. Передача данных поддерживалась в различных версиях Windows: сначала с использованием папки обмена (clipboard), позднее – посредством механизма динамического обмена данными (Dynamic Data Exchange, DDE), сейчас – через внедрение и связывание объектов (Object Linking and Embedding, OLE).
И все же, реализованная в ранних версиях Windows многозадачность не была традиционной вытесняющей, основанной на выделении отрезков времени, как в многопользовательских операционных системах. Такие операционные системы используют системный таймер для периодического прерывания выполнения одной задачи и запуска другой. 16-разрядные версии Windows поддерживали так называемую невытесняющую многозадачность (non-preemptive multitasking).[8, c. 60] Такой тип многозадачности был возможен благодаря основанной на сообщениях архитектуре Windows. В общем случае, Windows-программа находилась в памяти и не выполнялась до тех пор, пока не получала сообщение. Эти сообщения часто являлись прямым или косвенным результатом ввода информации пользователем с клавиатуры или мыши. После обработки сообщения программа возвращала управление обратно Windows.
16-разрядные версии Windows не имели возможности произвольно переключать управление с одной Windows-программы на другую, основываясь на квантах времени таймера. Переключение между задачами происходило в момент, когда программа завершала обработку сообщения и возвращала управление Windows. Такую невытесняющую многозадачность называют также кооперативной многозадачностью (cooperative multitasking) потому, что она требует некоторого согласования между приложениями. Одна Windows-программа могла парализовать работу всей системы, если ей требовалось много времени для обработки сообщения.
Хотя невытесняющая многозадачность была основным типом многозадачности в 16-разрядных версиях Windows, некоторые элементы вытесняющей (примитивной, preemptive) многозадачности в них тоже присутствовали.
Windows использовала вытесняющую многозадачность для выполнения DOS-программ, а также позволяла библиотекам динамической компоновки (DLL) получать прерывания аппаратного таймера для задач мультимедиа.
16-разрядные версии Windows имели некоторые особенности, которые помогали программистам если не разрешить, то, по крайней мере, справиться с ограничениями, связанными с невытесняющей многозадачностью. Наиболее известной является отображение курсора мыши в виде песочных часов. Конечно, это не решение проблемы, а только лишь возможность дать знать пользователю, что программа занята выполнением протяженной во времени работы, и что система какое-то время будет недоступна. Другим частичным решением является использование системного таймера Windows, что позволяет выполнять какие-либо действия периодически. Таймер часто используется в приложениях типа часов и приложениях, работающих с анимацией.
Другим решением по преодолению ограничений невытесняющей многозадачности является вызов функции PeekMessage. Обычно программа использует вызов функции GetMes-
sage для извлечения сообщений из очереди. Однако, если в данный момент времени очередь сообщений пуста, то функция GetMessage будет ждать поступления сообщения в очередь, а затем возвратит его. Функция PeekMessage работает иначе – она возвращает управление программе даже в том случае, если нет сообщений в очереди. Таким образом, выполнение работы, требующей больших затрат времени, будет продолжаться до того момента, пока в очереди не появятся сообщения для данной или любой другой программы.[3, c. 103, 1 том]
1.3. Presentation Manager и последовательная очередь сообщений
Первой попыткой фирмы Microsoft (в сотрудничестве с IBM) внедрить многозадачность в квази-DOS/Windows оболочку была система OS/2 и Presentation Manager (PM). Хотя OS/2, конечно, поддерживала вытесняющую многозадачность, часто казалось, что это вытеснение не было перенесено в PM. Дело в том, что PM выстраивал в очередь сообщения, формируемые в результате пользовательского ввода от клавиатуры или мыши. Это означает, что PM не предоставляет программе такое пользовательское сообщение до тех пор, пока предыдущее сообщение, введенное пользователем, не будет полностью обработано.
Хотя сообщения от клавиатуры или мыши – это только часть множества сообщений, которые может получить программа в PM или Windows, большинство других сообщений являются результатом событий, связанных с клавиатурой или мышью. Например, сообщение от меню команд является результатом выбора пункта меню с помощью клавиатуры или мыши. Сообщение от клавиатуры или мыши не будет обработано до тех пор, пока не будет полностью обработано сообщение от меню.
Основная причина организации последовательной очереди сообщений состоит в том, чтобы отследить все действия пользователя. Если какое-либо сообщение от клавиатуры или мыши вызывает переход фокуса ввода от одного окна к другому, то следующее сообщение клавиатуры должно быть направлено в окно, на которое установился фокус ввода. Таким образом, система не знает, в какое окно передавать сообщение на обработку до тех пор, пока не будет обработано предыдущее сообщение.
В настоящее время принято соглашение о том, что не должно быть возможности для какого-либо одного приложения парализовать работу всей системы, и что требуется использовать непоследовательную очередь сообщений, поддерживаемую системами Windows 95 и Windows NT. Если одна программа занята выполнением протяженной во времени операции, то существует возможность переключить фокус ввода на другое приложение.
Выше был рассмотрен Presentation Manager операционной системы OS/2 только из-за того, что это была первая оболочка, которая подготовила сознание некоторых ветеранов программирования под Windows (в том числе и автора) к введению многопоточности. Интересно, что ограниченная поддержка многопоточности в РМ дала программистам основную идею организации программ, использующих многопоточность. Хотя эти ограничения сейчас преимущественно преодолены в Windows 95, тем не менее уроки, полученные при работе с более ограниченными системами, остаются актуальными и по сей день.
В многопоточной среде программы могут быть разделены на части, называемые потоками выполнения (threads), которые выполняются одновременно. Поддержка многопоточности оказывается лучшим решением проблемы последовательной очереди сообщений в РМ и приобретает полный смысл при ее реализации в Windows 95.
В терминах программы "поток" – это просто функция, которая может также вызывать другие функции программы.[3, c. 412, 2 том] Программа начинает выполняться со своего главного (первичного) потока, который в традиционных программах на языке С является функцией main, а в Windows-программах – WinMain. Будучи выполняемой, функция может создавать новые потоки обработки, выполняя системный вызов с указанием функции инициализации потока (initial threading function). Операционная система в вытесняющем режиме переключает управление между потоками подобно тому, как она это делает с процессами.
В РМ системы OS/2 любой поток может либо создавать очередь сообщений, либо не создавать. РМ-поток должен создавать очередь сообщений, если он собирается создавать окно. С другой стороны, поток может не создавать очередь сообщений, если он осуществляет только обработку данных или графический вывод. Поскольку потоки, не создающие очереди сообщений, не обрабатывают сообщения, то они не могут привести к "зависанию" системы. На поток, не имеющий очереди сообщений, накладывается только одно ограничение – он не может посылать асинхронное сообщение в окно потока, имеющего очередь сообщений, или вызывать какую-либо функцию, если это приведет к посылке сообщения. (Однако эти потоки могут посылать синхронные сообщения потокам, имеющим очередь сообщений.)
Таким образом, программисты, работавшие с РМ, научились разбивать свои программы на один поток с очередью сообщений, создающий все окна и обрабатывающий сообщения для них, и один или несколько потоков, не имеющих очередей сообщений, и выполняющих продолжительные действия в фоновом режиме. Кроме того, программисты, работавшие с РМ, узнали о "правиле 1/10 секунды". Оно состоит в том, что поток с очередью сообщений тратит не более 1/10 секунды на обработку любого сообщения. Все, что требует большего времени, следовало выделять в отдельный поток. Если все программисты придерживались этого правила, то никакая РМ-программа не могла вызвать зависание системы более чем на 1/10 секунды.
1.4. Многопоточная архитектура
Как уже отмечалось выше, ограничения РМ дали программистам основные идеи для понимания того, как использовать множество потоков в программе, выполняемой в графической среде. Ниже приведены наши рекомендации по архитектуре многопоточных программ: первичный или главный (primary) поток вашей программы создает все окна и соответствующие им оконные процедуры, необходимые в программе и обрабатывает все сообщения для этих окон. Все остальные потоки – это просто фоновые задачи. Они не имеют интерактивной связи с пользователем, кроме как через первичный поток.
Один из способов добиться этого состоит в том, чтобы первичный поток обрабатывал пользовательский ввод и другие сообщения, возможно создавая при этом вторичные (secondary) потоки в процессе. Эти вторичные потоки выполняют не связанные с пользователем задачи.
Другими словами, первичный поток вашей программы является губернатором, а вторичные потоки – свитой губернатора. Губернатор поручает всю большую работу своим помощникам на то время, пока он осуществляет контакты с внешним миром. Поскольку вторичные потоки являются членами свиты, они не могут проводить свои пресс-конференции. Они скромно выполняют каждый свое задание, делают отчет губернатору и ждут новых указаний.
Потоки внутри отдельной программы являются частями одного процесса, поэтому они разделяют все ресурсы процесса, такие как память и открытые файлы. Поскольку потоки разделяют память, отведенную программе, то они разделяют и статические переменные. Однако, у каждого потока есть свой собственный стек, и значит, автоматические переменные являются уникальными для каждого потока. Каждый поток, также, имеет свое состояние процессора, которое сохраняется и восстанавливается при переключении между потоками.[5, c. 123]
Собственно разработка, программирование и отладка сложного многопоточного приложения являются, естественно, самыми сложными задачами, с которыми приходится сталкиваться программисту для Windows. Поскольку в системе с вытесняющей многозадачностью поток может быть прерван в любой момент для переключения на другой поток, то может случайно произойти любое нежелательное взаимодействие между двумя потоками.
Одной из основных ошибок в многопоточных программах является так называемое состояние гонки (race condition). Это случается, если программист считает, что один поток закончит выполнение своих действий, например, подготовку каких-либо данных, до того, как эти данные потребуются другому потоку. Для координации действий потоков операционным системам необходимы различные формы синхронизации. Одной из таких форм является семафор (semaphore), который позволяет программисту приостановить выполнение потока в конкретной точке программы до тех пор, пока он не получит от другого потока сигнал о том, что он может возобновить работу. Похожи на семафоры критические разделы (critical sections), которые представляют собой разделы кода, во время выполнения которого, поток не может быть прерван.
Но использование семафоров может привести к другой распространенной ошибке, связанной с потоками, которая называется тупиком (deadlock). Это случается, когда два потока блокируют выполнение друг друга, а для того, чтобы их разблокировать необходимо продолжить работу.
К счастью, 32-разрядные программы более устойчивы к определенным проблемам, включая проблемы с потоками, чем 16-разрядные программы. Например, предположим, что один поток выполняет простое действие: lCount++ ; где ICount – 32-разрядная глобальная переменная типа длинное целое, используемая другими потоками.[2, c. 286] В 16-разрядной программе, в которой такой оператор языка С транслируется в две инструкции машинного кода (сначала инкрементируется младшие 16 разрядов, а затем добавляется перенос в старшие 16 разрядов). Допустим, что операционная система прервала поток между этими двумя инструкциями машинного кода. Если переменная ICount имела значение $0000FFFF, то после выполнения первой инструкции машинного кода ICount будет иметь нулевое значение. Если в этот момент произойдет прерывание потока, то другой поток получит нулевое значение переменной ICount. Только после окончания этого потока значение ICount будет увеличено на единицу до своего истинного значения $00010000.
Такого рода ошибка может быть никогда не выявлена, поскольку довольно редко приводит к проблемам во время выполнения. Для 16-разрядных программ наилучший путь предотвратить такую ошибку – это поместить данное выражение в критический раздел, в рамках которого поток не может быть прерван. В 32-разрядной программе, однако, приведенное выражение является абсолютно корректным, поскольку оно компилируется в одну инструкцию машинного кода.
1.5. Преимущества Windows
Операционные системы Windows 95 и Windows NT не имеют последовательной очереди сообщений. Такое решение кажется очень хорошим: если программа выполняет длительную обработку сообщения, то курсор мыши принимает форму песочных часов при расположении над окном этой программы, и изменяется на обычную стрелку, если он располагается над окном другой программы. Простым щелчком кнопкой мыши можно перевести другое окно на передний план.
Однако, пользователь по-прежнему не может работать с приложением, выполняющим длительную операцию, поскольку выполнение длительной операции предотвращает получение сообщений программой. А это нежелательно. Программа должна быть всегда открыта для сообщений, а это требует использования вторичных потоков.
В Windows 95 и Windows NT не существует различия между потоками, имеющими очередь сообщений, и потоками без очереди сообщений. При создании каждый поток получает свою собственную очередь сообщений. Это снижает число ограничений, существующих для потоков в РМ-программе. (Однако, в большинстве случаев все еще обработка ввода и сообщений осуществляется в одном потоке, а протяженные во времени задачи передаются другим потокам, которые не создают окон.) Такая схема организации приложения, как мы увидим, почти всегда является наиболее разумной.
В Windows 95 и Windows NT есть функция, которая позволяет одному потоку уничтожить другой поток, принадлежащий тому же процессу. Как вы обнаружите, когда начнете писать многопоточные приложения под Windows, иногда это очень удобно. Ранние версии операционной системы OS/2 не содержали функции для уничтожения потоков.
Windows 95 и Windows NT поддерживают так называемую локальную память потока (thread local storage, TLS). Для того чтобы понять, что это такое, вспомним о том, что статические переменные, как глобальные так и локальные по отношению к функциям, разделяются между потоками, поскольку они расположены в зоне памяти данных процесса. Автоматические переменные (которые являются всегда локальными по отношению к функции) – уникальны для каждого потока, т. к. они располагаются в стеке, а каждый поток имеет свой стек.[8, c. 301]
Иногда бывает удобно использовать для двух и более потоков одну и ту же функцию, а статические данные использовать уникальные для каждого потока. Это и есть пример использования локальной памяти потока. Существует несколько вызовов функций Windows для работы с локальной памятью потока. Фирма Microsoft ввела расширение в компилятор С, которое позволяет использовать локальную память потока более прозрачным для программиста образом.
Иногда имеет место тенденция использовать в программе каждую возможность, предлагаемую операционной системой. Нет смысла использовать множество потоков в программе, которая в этом не нуждается. Если программа выводит на экран курсор в виде песочных часов на достаточно долгий период времени, или, если она использует функцию PeekMessage для того, чтобы избежать появления курсора в виде песочных часов, то тогда идея реструктуризации программы в многопоточную, вероятно, может оказаться хорошей. В противном случае, вы только усложните себе работу и, возможно, внесете в программу новые ошибки.
Есть даже некоторые ситуации, когда появление курсора мыши в виде песочных часов, может быть совершенно подходящим. Выше уже упоминалось "правило 1/10 секунды". Так вот, загрузка большого файла в память может потребовать больше времени, чем 1/10 секунды. Значит ли это, что функции загрузки файла должны были быть реализованы с использованием разделения на потоки? Совсем необязательно. Когда пользователь дает программе команду открыть файл, то он или она обычно хочет, чтобы операционная система выполнила ее немедленно. Выделение процесса загрузки файла в отдельный поток просто приведет к усложнению программы. Не стоит это делать даже ради того, чтобы похвастаться перед друзьями, что вы пишите многопоточные приложения.
Выше было показано, как лучше организовать архитектуру программы, использующей многопоточность, а именно, чтобы первичный поток создавал все окна в программе, содержал все оконные процедуры этих окон и обрабатывал все сообщения. Вторичные потоки выполняют фоновые задачи или задачи, протяженные во времени.
Однако, предположим, что требуется реализовать анимацию во вторичном потоке. Обычно анимация в Windows осуществляется с использованием сообщения WM_TIMER. Но если вторичный поток не создает окно, то он не может получить это сообщение. А без задания определенного темпа анимация могла бы осуществляться слишком быстро.
Решение состоит в использовании функции Sleep. Поток вызывает функцию Sleep для того, чтобы добровольно отложить свое выполнение. Единственный параметр этой функции – время, задаваемое в миллисекундах. Функция Sleep не осуществляет возврата до тех пор, пока не истечет указанное время. В течение него выполнение потока приостанавливается и выделения для него процессорного времени не происходит (хотя очевидно, что для потока все-таки требуется какое-то незначительное время, за которое система должна определить, пора возобновлять выполнение потока или нет).[7, c. 64]
Если параметр функции Sleep задан равным нулю, то поток будет лишен остатка выделенного ему кванта процессорного времени.
Когда поток вызывает функцию Sleep, задержка на заданное время относится к этому потоку. Система продолжает выполнять другие потоки этого и других процессов
В однозадачной операционной системе обычные программы не нуждаются в "светофорах" для координации их действий. Они выполняются так, как будто они являются хозяевами дороги, по которой они следуют. Не существует ничего, что могло бы вмешаться в то, что они делают.
Даже в многозадачной операционной системе большинство программ выполняются независимо друг от друга. Но некоторые проблемы все же могут возникнуть. Например, двум программам может понадобиться читать и писать в один файл в одно и то же время. Для таких случаев операционная система поддерживает механизм разделения файлов (shared files) и блокирования отдельных фрагментов файла (record locking).
Однако, в операционной системе, поддерживающей многопоточность, такое решение может внести путаницу и создать потенциальную опасность. Разделение
данных между двумя и более потоками является общим случаем. Например, один поток может обновлять одну или более переменных, а другой может использовать эти переменные. Иногда в этой ситуации может возникнуть проблема, а иногда – нет. (Помните, что операционная система может переключать управление потоками только между инструкциями машинного кода. Если простое целое число разделяется между двумя потоками, то изменение этой переменной обычно осуществляется одной инструкцией машинного кода, и потенциальные проблемы сводятся к минимуму.)
Однако, предположим, что потоки разделяют несколько переменных или структуру данных. Часто эти сложные переменные или поля структур данных должны быть согласованными между собой. Операционная система может прерывать поток в середине процесса обновления этих переменных. В этом случае поток, который затем использует эти переменные, будет иметь дело с несогласованными данными.
В результате бы возникла коллизия, и нетрудно представить себе, как такого рода ошибка может привести к краху программы. В этой ситуации нам необходимо нечто похожее на светофор, который мог бы синхронизировать и координировать работу потоков. Таким средством и является критический раздел. Критический раздел – это блок кода, при выполнении которого поток не может быть прерван.
Имеется четыре функции для работы с критическими разделами.[7, c. 132] Чтобы их использовать, вам необходимо определить объект типа критический раздел, который является глобальной переменной типа CRITICAL_SECTION. Например,
CRITICAL_SECTION CS ;
Тип данных CRITICAL_SECTION является структурой, но ее поля используются только внутри Windows. Объект типа критический раздел сначала должен быть инициализирован одним из потоков программы с помощью функции:
InitializeCriticalSection (&cs);
Эта функция создает объект критический раздел с именем cs. В документации содержится следующее предупреждение: "Объект критический раздел не может быть перемещен или скопирован. Процесс также не должен модифицировать объект, а должен обращаться с ним, как с "черным ящиком"."
После инициализации объекта критический раздел поток входит в критический раздел, вызывая функцию:
EnterCriticalSection (&cs) ;
В этот момент поток становится владельцем объекта. Два различных потока не могут быть владельцами одного объекта критический раздел одновременно. Следовательно, если один поток вошел в критический раздел, то следующий поток, вызывая функцию EnterCriticalSection с тем же самым объектом
критический раздел, будет задержан внутри функции. Возврат из функции произойдет только тогда, когда первый поток покинет критический раздел, вызвав функцию:
LeaveCriticalSection (&cs);
В этот момент второй поток, задержанный в функции EnterCriticalSection, станет владельцем критического раздела, и его выполнение будет возобновлено.
Когда объект критический раздел больше не нужен вашей программе, его можно удалить с помощью функции:
DeleteCriticalSection (&cs);
Это приведет к освобождению всех ресурсов системы, задействованных для поддержки объекта критический раздел.
Механизм критических разделов основан на принципе взаимного исключения (mutual exclusion). Этот термин нам еще встретится при дальнейшем рассмотрении синхронизации потоков. Только один поток может быть владельцем критического раздела в каждый конкретный момент времени. Следовательно, один поток может войти в критический раздел, установить значения полей структуры и выйти из критического раздела. Другой поток, использующий эту структуру, также мог бы войти в критический раздел перед осуществлением доступа к полям структуры, а затем выйти из критического раздела.[9, c. 307]
Обратите внимание, что возможно определение нескольких объектов типа критический раздел, например, cs1 и cs2. Если в программе имеется четыре потока, и два первых из них разделяют некоторые данные, то они могут использовать первый объект критический раздел, а два других потока, также разделяющих другие данные, могут использовать второй объект критический раздел.
Обратите внимание, что надо быть весьма осторожным при использовании критического раздела в главном потоке. Если вторичный поток проводит слишком много времени в его собственном критическом разделе, то это может привести к "зависанию" главного потока на слишком большой период времени.
1.6. Объект Mutex
Существует одно ограничение в использовании критических разделов. Оно заключается в том, что их можно применять для синхронизации потоков только в рамках одного процесса. Но бывают случаи, когда необходимо синхронизировать действия потоков различных процессов, которые разделяют какие-либо ресурсы (например, память). Использовать критические разделы в такой ситуации нельзя. Вместо них подключаются объекты типа mutex (mutex object).
Составное слово "mutex" происходит из словосочетания "mutual exclusion", что означает взаимное исключение, и очень точно отражает назначение объектов.[10, c. 51] Мы хотим предотвратить возможность прерывания потока в программе до тех пор, пока не будет выполнено обновление или использование разделяемых данных.
Мы можем определить понятие большой работы как действия, выполняя которые, программа нарушит "правило 1/10 секунды". Примерами большой работы могут служить: проверка орфографии в текстовых процессорах, сортировка и индексирование файлов баз данных, пересчет электронной таблицы, печать и даже сложное рисование. Конечно, как мы уже знаем, лучшее решение состоит в следовании "правилу 1/10 секунды", т. е. в передаче большой работы вторичным потокам обработки. Эти вторичные потоки не создают окон и, значит, не ограничены "правилом 1/10 секунды".
Часто бывает, что вторичному потоку надо проинформировать первичный поток о том, что он завершился, или первичному потоку надо прервать работу, выполняемую вторичным потоком.
Глобальные переменные в многопоточных программах (так же как и любая выделенная память) разделяются между всеми потоками в программе. Локальные статические переменные функций также разделяются между всеми потоками, использующими эту функцию. Локальные автоматические переменные в функции являются уникальными для каждого потока, потому что они хранятся в стеке, а каждый поток имеет свой собственный стек.
Может возникнуть необходимость иметь постоянную область памяти, уникальную для каждого потока. Например, функция strtok языка С, которая уже упоминалась в этой главе, требует такого типа память. Нет сомнений, что С его не поддерживает. В Windows 95 имеется четыре функции, поддерживающие эту память, которая называется локальной памятью потока (thread local storage, TLS).[3, c. 500, 2 том.]
Первичный поток вызывает функцию JTsAlloc для получения значения индекса:
dwTlsIndex = TIsAlloc () ;
Он может храниться в глобальной переменной или может быть передан функции потока в параметре-структуре.
Функция потока начинается с выделения памяти для структуры данных и с вызова функции TIsSetValue, используя индекс, полученный ранее:
TIsSetValue (dwTlsIndex, GlobalAlloc (GPTR, sizeof (DATA))) ;
Это действие устанавливает соответствие указателя с конкретным потоком и конкретным индексом в потоке. Теперь, любая функция, которой нужно использовать этот указатель (включая саму базовую функцию потока), может использовать код, подобный такому:
PDATA pdata ;
pdata = (PDATA) TIsGetValue (dwTlsIndex) ;
Теперь она может изменять значения pdata->
a и pdata->
b. Перед завершением функции потока необходимо освободить захваченную память:
GlobalFree (TIsGetValue (dwTlsIndex)) ;
Когда все потоки, использующие эти данные будут завершены, первичный поток освобождает индекс:
TIsFree (dwTlsIndex) ;
Полезно посмотреть как организована локальная память потока. (Мне неизвестно, как в действительности Windows 95 это делает, но описываемая схема вполне правдоподобна.) Во-первых, функция TIsAlloc могла бы просто выделить блок памяти (длиной 0 байт) и вернуть значение индекса, который является указателем на этот блок. Каждый раз при вызове функции TIsSet
Value с этим индексом блок памяти увеличивается на 8 байт с помощью функции GlobalReAlloc. В этих 8 байтах хранятся идентификатор потока, вызывающего функцию, полученный с помощью функции GetCurrentThreadID, и указатель, переданный функции TIsSetValue. Функция TIsGetValue просто использует идентификатор потока для поиска в таблице, а затем возвращает указатель. Функция TZsFree освобождает блок памяти.
Таким образом в I главе было показано, что начиная с Windows 95 реализование принципиально другой вид многозадачности, в котором операционная система действительно контролирует и управляет процессами, потоками и их переключением. Способность операционной системы прервать выполняемый поток практически в любой момент времени и передать управление другому ожидающему потоку определяется термином preemptive multitasking — преимущественная, или вытесняющая, многозадачность. Реализация ее выглядит так: все существующие в данный момент потоки, часть из которых может принадлежать одному и тому же процессу, претендуют на процессорное время и, с точки зрения пользователя должны выполняться одновременно. Для создания этой иллюзии система через определенные промежутки времени забирает управление, анализирует свою очередь сообщений, распределяет сообщения по другим очередям в пространстве процессов и, если считает нужным, переключает потоки.
Реализация вытесняющей многозадачности в Windows 2000 дает не только возможность плавного переключения задач, но и устойчивость среды к зависаниям, так как ни одно приложение не может получить неограниченные права на процессорное время и другие ресурсы. Так система создает эффект одновременного выполнения нескольких приложений. Если компьютер имеет несколько процессоров, то системы Windows NT/2000 могут действительно совмещать выполнение нескольких приложений. Если процессор один, то совмещение остается иллюзией. Когда заканчивается квант времени, отведенный текущей программе, система ее прерывает, сохраняет контекст и отдает управление другой программе, которая ждет своей очереди. Величина кванта времени (time slice) зависит от ОС и типа процессора, в Windows NT она в среднем равна 20 мс.
Глава II. Особенности реализации многозадачности Windows 2003
2.1. Реализация многозадачности в Windows 2003
В современных полновесных реализациях Windows (Windows 2000, Windows XP, Windows 2003) планировщик ядра выделяет процессорное время потокам. Управление волокнами возложено на приложения пользователя: Windows предоставляет набор функций, с помощью которых приложение может управлять созданными волокнами. Фактически для волокон реализуется невытесняющая многозадачность средствами приложения; с точки зрения операционной системы, все волокна должны быть созданы в рамках потоков (один поток может быть "расщеплен" на множество волокон средствами приложения) и система никак не вмешивается в их планирование.
В Windows определен список событий, которые приводят к перепланированию потоков [11, c. 48]:
· создание и завершение потока;
· выделенный потоку квант исчерпан;
· поток вышел из состояния ожидания;
· поток перешел в состояние ожидания;
· изменен приоритет потока;
· изменена привязка к процессору.
В целях уменьшения затрат на планирование потоков несколько изменен граф состояний потока. На рис. 1.1 - граф состояний потока в Windows. Переход из состояния "готовность" в состояние "выполнение" сделан в два этапа - выбранный к выполнению поток подготавливается к выполнению и переводится в состояние "выбран"; эта подготовка может осуществляться до наступления момента перепланирования, и в нужный момент достаточно просто переключить контекст выполняющегося потока на выбранный.
Рис. 1.1. Граф состояний потока
Также в два этапа может происходить переход из состояния "ожидание" в "готовность": если ожидание было долгим, то стек потока может быть выгружен из оперативной памяти. В этом случае поток переводится в промежуточное состояние до завершения загрузки стека - в списке готовых к выполнению потоков находятся только те, которые можно начать выполнять без лишнего ожидания.
При выборе потока для выполнения учитываются приоритеты потоков (абсолютные приоритеты) - система начинает выполнять код потока с наибольшим приоритетом из числа готовых к исполнению.
Процесс выбора потока для выполнения усложняется в случае SMP систем, когда помимо приоритета готового к исполнению потока учитывается, на каком процессоре ранее выполнялся код данного потока.
В Windows выделяют понятие "идеального" процессора - им назначается процессор, на котором запускается приложение в первый раз.[12, c. 20] В дальнейшем система старается выполнять код потока именно на этом процессоре - для SMP систем это решение улучшает использование кэш-памяти, а для NUMA систем позволяет, по большей части, ограничиться использованием оперативной памяти, локальной для данного процессора. Заметим, что диспетчер памяти Windows при выделении памяти для запускаемого процесса старается учитывать доступность памяти для назначенного процессора в случае NUMA системы.
В многопроцессорной системе используется либо первый простаивающий процессор, либо, при необходимости вытеснения уже работающего потока, проверяются идеальный процессор, последний использовавшийся и процессор с наибольшим номером. Если на одном из них работает поток с меньшим приоритетом, то последний вытесняется и заменяется новым потоком; в противном случае выполнение потока откладывается (даже если в системе есть процессоры, занятые потоками с меньшим приоритетом).
Современные реализации Windows в рамках единого дерева кодов могут быть использованы для различных классов задач - от рабочих станций, обслуживающих преимущественно интерфейс пользователя, до серверных установок на многопроцессорных машинах. Чтобы можно было эффективно использовать одну ОС в столь разных классах систем, планировщик Windows динамически изменяет длительность квантов и приоритеты, назначаемые потокам. Администратор системы может в некоторой степени изменить поведение системы при назначении длительности квантов и приоритетов потоков.
2.2. Управление квантованием в Windows 2003
Квантование потоков осуществляется по тикам системного таймера, продолжительность одного тика составляет обычно 10 или 15 мс, больший по продолжительности тик назначают многопроцессорным машинам. Каждый тик системного таймера соответствует 3 условным единицам; величина кванта может варьироваться от 2 до 12 тиков (от 6 до 36 единиц).[14, c. 103]
Параметр реестра HKLM\SYSTEM\ CurrentControlSet\ Control\PriorityControl\ Win32PrioritySeparation предназначен для управления квантованием. На рис. 1.2 дан формат этого параметра для Windows 2000-2003, а в таблице 1.1 приводятся длительности квантов в условных единицах для разных значений полей параметра Win32PrioritySeparation.
Рис. 1.2. Управление квантованием в Windows (длительность кванта показана в табл. 1.1)
Таблица 1.1. Длительность кванта | ||||||
| Короткий квант | Длинный квант | ||||
Значение младших 2-х бит параметра Win32PrioritySeparation | 0 | 1 | 2 | 0 | 1 | 2 |
Переменная длительность | 6 | 12 | 18 | 12 | 24 | 36 |
Фиксированная длительность | 18 | 18 | 18 | 36 | 36 | 36 |
Этот параметр может быть изменен с помощью панели управления, однако, лишь в очень ограниченных рамках:
"System Properties|Advanced|Performance:Settings|Advanced|Adjust for best performance of:" позволяет выбрать только:
· "applications"
Короткие кванты переменной длины, значение 0x26 т.е. 10 01 10 (короткие кванты переменной длительности, 18 ед.).
· "background services"
Длинные кванты фиксированной длины, значение 0x18 т.е. 01 10 00 (длинные кванты фиксированной длительности, 36 ед.). Более тонкая настройка возможна с помощью редактора реестра.[14, c. 155]
Управление длительностью кванта связано с активностью процесса, которая определяется наличием интерфейса пользователя (GUI или консоль) и его активностью. Если процесс находится в фоновом режиме, то длительность назначенного ему кванта соответствует "нулевым" колонкам таблицы 6.1 (выделены серым цветом; т.е. длительности 6 или 24 - для переменной длины кванта или 18 и 36 - для фиксированной). Когда процесс становится активным, то ему назначается продолжительность квантов, исходя из значения двух младших бит параметра Win32PrioritySeparation в соответствии с приведенной таблицей.
Еще один случай увеличения длительности кванта - процесс долгое время не получал процессорного времени (это может случиться, если все время есть активные процессы более высокого приоритета). В этой ситуации система раз в 3-4 секунды (в зависимости от продолжительности тика) назначает процессу повышенный приоритет и квант удвоенной длительности. По истечении этого кванта приоритет возвращается к прежнему значению и восстанавливается рекомендуемая длительность кванта.
2.3. Управление приоритетами в Windows 2003
В Windows выделяется 32 уровня приоритетов. 0 соответствует самому низкому приоритету (с таким приоритетом работает только специальный поток обнуления страниц), 31 - самому высокому. Этот диапазон делится на три части[15, c. 76]:
· Приоритет 0 - соответствует приоритету потока обнуления страниц.
· Приоритеты с 1 по 15 - соответствуют динамическим уровням приоритетов. Большинство потоков работают именно в этом диапазоне приоритетов, и Windows может корректировать в некоторых случаях приоритеты потоков из этого диапазона.
· Приоритеты с 16 по 31 - соответствуют приоритетам "реального времени". Этот уровень достаточно высок для того, чтобы поток, работающий с таким приоритетом, мог реально помешать нормальной работе других потоков в системе - например, помешать обрабатывать сообщения от клавиатуры и мыши. Windows самостоятельно не корректирует приоритеты этого диапазона.
Для некоторого упрощения управления приоритетами в Windows выделяют "классы приоритета" (priority class), которые задают базовый уровень приоритета, и "относительные приоритеты" потоков, которые корректируют указанный базовый уровень. Операционная система предоставляет набор функций для управления классами и относительными приоритетами потоков.
Планировщик операционной системы также может корректировать уровень приоритета (из диапазона 1-15), однако базовый уровень (т.е. класс) не может быть изменен. Такая коррекция приоритета выполняется в случае:
· Завершения операции ввода-вывода - в зависимости от устройства, приоритет повышается на 1 - 8 уровней.
· По окончании ожидания события или семафора (см. далее) - на один уровень.
· При пробуждении GUI потоков - на 2 уровня.
· По окончании ожидания потоком активного процесса (определяется по активности интерфейса) - на величину, указанную младшими 2 битами параметра Win32PrioritySeparation (см. управление длительностью кванта).
В случае коррекции приоритета по одной из перечисленных причин, повышенный приоритет начинает постепенно снижаться до начального уровня потока - с каждым тиком таймера на один уровень.
Еще один случай повышения приоритета (вместе с увеличением длительности кванта) - процесс долгое время не получал процессорного времени. В этой ситуации система раз в 3-4 секунды назначает процессу приоритет, равный 15, и квант удвоенной длительности. По истечении этого кванта приоритет возвращается к прежнему значению и восстанавливается рекомендуемая длительность кванта.
В зависимости от настройки планировщика, NORMAL_PRIORITY_CLASS с базовым уровнем приоритета 8 может быть "расщеплен" на два базовых уровня - для потоков активных процессов (базовый уровень 9) и для потоков фоновых процессов (базовый уровень 7). Для класса HIGH_PRIORITY_CLASS относительные приоритеты потока THREAD_PRIORITY_HIGHEST и THREAD_PRIORITY_TIME_CRITICAL дают одинаковое значение приоритета 15.
2.4. Особенности многозадачности в среде Windows 2003
Общеизвестно, что в Windows 2003 реализована вытесняющая многозадачность. Именно это привлекло внимание многих фирм-разработчиков ПО, поскольку предшественницы этой ОС справедливо считались тяжелыми и неповоротливыми.
Появление вытесняющей многозадачности в Windows 2003 резко повысило надежность оболочки. Теперь в девяносто девяти случаях из ста "неработоспособную" программу можно корректно снять с выполнения, не затрагивая при этом другие программы. Конечно, если программа "подвисает", то принудительное удаление ее из системы бесследно не проходит и в дальнейшем может привести к краху всей системы. Но в любом случае после снятия такой программы появляется возможность корректного завершения других программ и перезапуска системы без потери данных.
Основные понятия многозадачности в Windows 2003 - процесс (задача) и поток (нить). Под процессом понимается выполнение программы в целом (WinWord, Excel, Visual C++ и т. д.) Потоками в свою очередь являются части процесса, выполняющиеся параллельно.[14, c. 91]
Любой процесс имеет хотя бы один поток. В этом случае его можно отождествить с потоком. Процессы интересны с точки зрения взаимодействия одновременно выполняющихся программ, потоки (участки кода, выполняющиеся параллельно в одном процессе) - с точки зрения их синхронизации.
Заметим, что одновременно выполняющиеся потоки могут быть зависимы друг от друга - например, один поток подготавливает данные, другой их сортирует, а третий выводит результат в файл. Передав готовые данные второму потоку на сортировку, первый начинает обработку нового блока. Тем временем второй поток сообщает третьему, что можно выводить результаты. Следовательно, работу этих трех потоков необходимо синхронизировать.
Для синхронизации процессов и потоков в Windows 2003 предусмотрено четыре механизма[11, c. 110]:
· классический семафор
· критический раздел
· исключающий семафор (объект типа mutex)
· событие (event object)
Мы рассмотрим два из них: критический раздел и исключающий семафор.
Критический раздел - это часть кода, доступ к которому в данное время имеет только один поток. Другой поток может обратиться к критическому разделу, только когда первый выйдет из него.
Для работы с критическими разделами используются следующие функции:
· VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) - инициализация синхронизатора типа критический раздел.
· lpCriticalSection - указатель на переменную типа CRITICAL_SECTION.
· VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) - запрос на вход в критический раздел.
lpCriticalSection - указатель на переменную типа CRITICAL_SECTION.
· VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) - выход из критического раздела (освобождение семафора).
lpCriticalSection - указатель на переменную типа CRITICAL_SECTION.
· VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection) - удаление критического раздела (обычно при выходе из программы).
lpCriticalSection - указатель на переменную типа CRITICAL_SECTION.
Итак, для создания критического раздела необходимо инициализировать структуру CRITICAL_SECTION.
Создав объект CRITICAL_SECTION, мы можем работать с ним, т. е. можем обозначить код, доступ к которому для одновременно выполняющихся задач требуется синхронизировать.
Рассмотрим такой пример. Мы хотим записывать и считывать значения из некоего глобального массива mas. Причем запись и считывание должны производиться двумя разными потоками. Вполне естественно, что лучше если эти действия не будут выполняться одновременно. Поэтому введем ограничение на доступ к массиву.
И хотя приведенный нами пример подобного ограничения чрезвычайно упрощен, он хорошо иллюстрирует работу синхронизатора типа критический раздел: пока один поток "владеет" массивом, другой доступа к нему не имеет.
Еще один вид синхронизаторов - исключающий семафор. Основное его отличие от критического раздела заключается в том, что последний можно использовать только в пределах одного процесса (одного запущенного приложения), а исключающими семафорами могут пользоваться разные процессы. Другими словами, критические разделы - это локальные семафоры, которые доступны в рамках только одной программы, а исключающие семафоры могут быть глобальными объектами, позволяющими синхронизировать работу программ (т. е. разные запущенные приложения могут разделять одни и те же данные).
Есть еще одна особенность при работе с объектами синхронизации. Дело в том, что Windows 2003 довольно "тяжело" взаимодействует со своей графической системой в многозадачном режиме. Это объясняется тем, что в Windows 2003 графическая подсистема частично осталась 16-разрядной и обращение к такому коду приводит к захвату системного исключающего семафора Win16Mutex, который предотвращает одновременный доступ нескольких процессов (потоков) к такому коду.
Одним из положительных свойств вытесняющей многозадачности является то, что она предоставляет механизм корректного изменения данных. Ведь если несколько потоков имеют доступ к одной переменной, то нет никакой гарантии, что в процессе изменения значения этой переменной одним потоком не произойдет переключение на другой поток, который может читать ее значение. Другой поток в этом случае получит неверную информацию. Для предотвращения таких конфликтов в Windows 95 введен ряд функций, позволяющих корректно изменять переменные, доступ к которым имеют несколько потоков. Перечислим функции, предохраняющие от переключения во время изменения значения переменной[3, c. 198, 1 том]:
· LONG InterlockedIncrement (LPLONG lpAddend) - увеличивает значение по адресу lpAddend на единицу;
· LONG InterlockedDecrement (LPLONG lpAddend) - уменьшает значение по адресу lpAddend на единицу;
· LONG InterlockedExchange (LPLONG Target, LONG Value) - заменяет значение, находящееся по адресу Target, на значение, переданное в параметре Value;
· LONG InterlockedExchangeAdd (PLONG Addend, LONG Increment) - прибавляет к значению по адресу Addend значение Increment;
· PVOID InterlockedCompareExchange (PVOID *Destination, PVOID Exchange, PVOID Comperand) - сравнивает значение по адресу Destination со значением, переданным в параметре Comperand, и если эти значения равны, то по адресу Destination помещается значение, переданное в параметре Exchange.
Таким образом во II главе было рассмотрено: реализация многозадачности в Windows 2003, управление волокнами возложено на приложения пользователя: Windows предоставляет набор функций, с помощью которых приложение может управлять созданными волокнами. Фактически для волокон реализуется невытесняющая многозадачность средствами приложения; с точки зрения операционной системы, все волокна должны быть созданы в рамках потоков (один поток может быть "расщеплен" на множество волокон средствами приложения) и система никак не вмешивается в их планирование.
Также в два этапа может происходить переход из состояния "ожидание" в "готовность": если ожидание было долгим, то стек потока может быть выгружен из оперативной памяти. В этом случае поток переводится в промежуточное состояние до завершения загрузки стека - в списке готовых к выполнению потоков находятся только те, которые можно начать выполнять без лишнего ожидания.
При выборе потока для выполнения учитываются приоритеты потоков (абсолютные приоритеты) - система начинает выполнять код потока с наибольшим приоритетом из числа готовых к исполнению.
Было рассмотрено управление квантованием в Windows 2003. Квантование потоков осуществляется по тикам системного таймера, продолжительность одного тика составляет обычно 10 или 15 мс, больший по продолжительности тик назначают многопроцессорным машинам. А также управления приоритетами. В Windows выделяют "классы приоритета" (priority class), которые задают базовый уровень приоритета, и "относительные приоритеты" потоков, которые корректируют указанный базовый уровень. Операционная система предоставляет набор функций для управления классами и относительными приоритетами потоков.
Заключение
Очень многие программисты, перейдя с DOS на Windows, в течение долгого времени все еще стараются программировать по-старому. Конечно, полностью это сделать не получается - такие вещи, как обработка сообщений, являются неотъемлемой частью любого Windows-приложения. Однако, 32-разрядная платформа в силу своей структуры предоставляет программистам новые захватывающие дух возможности. И если вы их не используете, а стараетесь решить проблему так, как привыкли, то вполне естественно, что из этого не получается ничего хорошего.
Эти возможности - возможности многозадачности. Прежде всего очень важно уяснить для себя, КОГДА вам следует подумать об ее использовании в своем приложении. Ответ так же очевиден, как и определение термина "многозадачность" - она нужна тогда, когда вы хотите, чтобы несколько участков кода выполнялось ОДНОВРЕМЕННО. Например, вы хотите, чтобы какие-то действия выполнялись в фоновом режиме, или чтобы в течение ресурсоемких вычислений, производимых вашей программой, она продолжала реагировать на действия пользователя.
Были рассмотрены почти все современные операционные системы (Windows 95, Windows NT, Windows 2000), которые поддерживают преимущественную многозадачность {preemptive multi-tasking). Этот термин, который часто переводят как вытесняющая многозадачность, означает, что процесс или, точнее, его поток, который в данный момент активен, имеет преимущество перед другими конкурирующими потоками с одинаковым приоритетом. Системы Windows 3.1 и Macintosh поддерживают кооперативную многозадачность {cooperative multi-tasking), в которой все управление отдано системе. В такой системе легче программировать, но она менее эффективна.
Были рассмотрены основные признаки многозадачности ОС является способность совмещать выполнение нескольких прикладных программ. Большое значение при этом имеет способ совмещения, то есть на каком уровне или как конкретно реализовано совмещение. Если однопроцессорная, но многозадачная, система выделяет каждой прикладной программе определенный квант времени {lime slice), спустя который она переключается на выполнение следующей программы, то это система с разделением времени {time-sharingsystem). Системы с разделением времени появились в начале 60-х. Они управлялись main /rame-компьютерами, обслуживающими многочисленные удаленные терминалы. В качестве терминалов сначала использовались обычные телетайпы, которые умели только вводить или выводить информацию. Благодаря огромной разнице в скорости работы таких устройств, как телетайп и процессор, системы с разделением времени успевали переключаться между многими терминалами и вводить или выводить информацию так, что каждому пользователю казалось, что он единолично управляет удаленным процессором. Затем появились персональные компьютеры, которые стали использоваться в качестве удаленных терминалов. В связи с этим для операционной системы главного процессора (например, IBM-370) отпала необходимость заниматься посимвольным вводом-выводом. Теперь акцент в разработке операционных систем был перенесен на управление выполняемыми программными модулями, принадлежащими разным пользователям и одновременно находящимися в памяти главного компьютера. Появились такие понятия, как очередь заданий ,очередь на обслуживание каким-либо устройством: принтером, плоттером, накопителем на магнитном носителе, приоритет задания, ожидаемое время завершения задания и т. д.
В настоящее время, когда каждый пользователь имеет достаточно мощный персональный компьютер, акценты в развитии ОС снова изменились. Теперь большое значение приобретает развитие сетевых, многозадачных ОС. В сущности, теперь пользователь имеет возможность установить на отдельном персональном компьютере многозадачную ОС и разрабатывать приложения, совмещающие выполнение нескольких процессов. Каждый процесс, в свою очередь, может состоять из нескольких потоков, выполняемых в адресном пространстве процесса.
Первые операционные системы, реализованные на персональных компьютерах, сильно уступали в концептуальном плане и по своим реальным возможностям системам с разделением времени, давно реализованным в mainframe- компьютерах. В Win 16, например, тоже существует понятие многозадачности. Реализовано оно следующим образом: обработав очередное сообщение, приложение передает управление операционной системе, которая может передать управление другому приложению. Такой вид многозадачности, при котором операционная система передает управление от одного приложения другому не в любой момент времени, а только когда текущее приложение отдает управление системе, получил, как было упомянуто, название кооперативной многозадачности (cooperative multi-tasking).
Если при таком подходе обработка сообщения затягивается, то пользователь увидит реакцию системы только после завершения обработки текущим приложением, текущего сообщения. Обычно при выполнении длительных операций программист изменяет форму курсора (песочные часы), вызвав API-функцию BeginWaitCursor. Иногда, если это предусмотрел разработчик программы, в таких случаях застрявшее приложение даже вызывает функцию PeekMessage, сообщая системе, что она может обработать очередное сообщение, а текущее приложение способно и подождать. Но главная неприятность при таком подходе заключается в том, что в случае бесконечного цикла, вызванного ошибкой в программе, ОС не имеет шансов получить управление и также зависнет. Пользователю придется перезагружать систему.
Было показано в Windows начиная с Windows 95 реализование принципиально другой вид многозадачности, в котором операционная система действительно контролирует и управляет процессами, потоками и их переключением. Способность операционной системы прервать выполняемый поток практически в любой момент времени и передать управление другому ожидающему потоку определяется термином preemptive multitasking — преимущественная, или вытесняющая, многозадачность. Реализация ее выглядит так: все существующие в данный момент потоки, часть из которых может принадлежать одному и тому же процессу, претендуют на процессорное время и, с точки зрения пользователя должны выполняться одновременно. Для создания этой иллюзии система через определенные промежутки времени забирает управление, анализирует свою очередь сообщений, распределяет сообщения по другим очередям в пространстве процессов и, если считает нужным, переключает потоки.
Реализация вытесняющей многозадачности в Windows 2000 дает не только возможность плавного переключения задач, но и устойчивость среды к зависаниям, так как ни одно приложение не может получить неограниченные права на процессорное время и другие ресурсы. Так система создает эффект одновременного выполнения нескольких приложений. Если компьютер имеет несколько процессоров, то системы Windows NT/2000 могут действительно совмещать выполнение нескольких приложений. Если процессор один, то совмещение остается иллюзией. Когда заканчивается квант времени, отведенный текущей программе, система ее прерывает, сохраняет контекст и отдает управление другой программе, которая ждет своей очереди. Величина кванта времени (time slice) зависит от ОС и типа процессора, в Windows NT она в среднем равна 20 мс. Следует отметить, что добиться действительно одновременного выполнения потоков можно только на машине с несколькими процессорами и только под управлением Windows NT/2000, ядра которых поддерживают распределение потоков между процессорами и процессорного времени между потоками на каждом процессоре. Windows 95 работает только с одним процессором. Даже если у компьютера несколько процессоров, под управлением Windows 95 задействован лишь один из них, а остальные простаивают.
Перепишите заключение в соответствии с новыми задачами, обратите внимание, на ключевые слова (подчёркнуты). Кроме того, например, если вы выделили процессы информационных систем, тогда перечислите их ч/з запятую, рассмотрели понятие ИС управления, тоже самое через запятую, что конкретно там рассмотрели….1 стр. максимум.
Список используемой литературы
1. Turbo Pascal for Windows в 2-х томах. Нейл Рубенкинг Пер. с англ. – М.:Мир, 1993, 536 с., ил.
2. Теория и практика C++. Герберт Шилдт. пер. с англ. – СПб.: BHV – Санкт-Петербург, 1996. 416 с., ил.
3. Программирование для Windows 95; в 2-х томах. Чарльз Петзолд. пер. с англ. – СПб.: BHV – Санкт-Петербург, 1997.– 752 с., ил.
4. Микропроцессоры 80x86 Архитектура, функционирование. В.М.Михальчук А.А.Ровдо С.В.Рыжиков Мн.: Битрикс, 1994. - 400с.
5. С. Томпсон, К. Элшир. Осваиваем мультимедиа: Пер. с англ. – М.: Восточная книжная компания, 1997. – 288 с.: ил.
6. Штайнер Г. Windows 2000. – М.: Лаборатория Базовых Знаний, 2000, - 608 с.: ил. – (Справочник)
7. Бойс Дж. Windows 2000: Пер. с англ. – М.: ДМ Пресс, 2001. – 304 с.: ил.
8. К. Айвенс. Эксплуатация Windows NT. Проблемы и решения: пер. с англ. – СПб.: BHV – Санкт-Петербург, 1998. – 592 с.: ил.
9. Информатика: Базовый курс . С. В. Симонович и др. – СПб.: Питер, 2003. – 640 с.: ил.
10. «IBM PC для пользователей» В.Э.Фигурнов – 210 c.
11. «Windows 2003 для занятых» Рон Мэнсфилд – 188 c.
12. «Операционная система Windows 2003» А.В.Потапкин – 354 c.
13. «Курс молодого бойца» К.Ахметов – 179 c.
14. «Эффективная работа в Windows 2003» К.Стинсон – 498 c.
15. «Windows 2003» Стефан Фойц – 523 c.
16. http://www.computerra.ru/softerra/program/6973/
17. http://www.kentos.ru/PROGR/Visual_C_7/Glava12/Index5.htm
18. http://www.zachetka.ru/referat/preview.aspx?docid=2769&page=9
19. http://p6.ru/referats/content/47/rom-0252.zip/rom_0252_doc.htm
20. http://www.goldref.ru/lectures/infor/17.shtml