Особенности реализации многозадачности ОС Windows

Автор работы: Пользователь скрыл имя, 14 Октября 2009 в 17:38, Не определен

Описание работы

Содержание
Введение 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

Файлы: 1 файл

КурсоваОсобенности реализации многозадачности Windows 1.doc

— 235.50 Кб (Скачать файл)

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

Однако, предположим, что требуется реализовать  анимацию во вторичном потоке. Обычно анимация в 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