Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Операционные Системы

.pdf
Скачиваний:
37
Добавлен:
02.03.2016
Размер:
1.94 Mб
Скачать

Можно, однако, воспользоваться защитой по умолчанию и передавать

NULL в качестве параметра.

Таблица описателей объектов ядра

Таблица описателей принадлежит процессу и содержит список всех

описателей объектов ядра, связанных с процессом (см. Таблица 2).

Таблица 2 Примерная структура таблицы описателей объектов ядра.

Индекс

Указатель на блок памяти объекта

Маска доступа

Флаги

 

ядра

 

 

 

 

 

 

1

0х????????

0х????????

0х????????

 

 

 

 

2

0х????????

0х????????

0х????????

 

 

 

 

Закрытие объектов ядра.

Независимо от того, какой функцией был создан объект ядра. После окончания работы с ним его нужно закрыть вызовом функции CloseHandle:

BOOL CloseHandle(HANDLE hobj);

Эта функция проверяет таблицу описателей объектов ядра процесса.

Если описатель найден, то функция получает адрес структуры, описывающей объект ядра, и уменьшает счѐтчик пользователей на 1; как только счѐтчик достигнет нуля, система уничтожит объект. Независимо от того уничтожила система объект или нет, описатель становится не действительным (удаляется из таблицы описателей). При успешном закрытии описателя функция возвращает значение TRUE.

Совместное использование ядра несколькими процессами

Для разделения между процессами одного и того же объекта ядра существуют три механизма:

11

Наследование описателя

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

Именованные объекты

Многие объекты ядра допускают именование. Если мы создадим именованный объект ядра в одном процессе, а затем вызовем функцию создания (открытия) объекта в другом процессе с тем же именем, то система вернѐт ссылку на существующий объект ядра.

Дублирование описателей объектов

Используется функция DuplicateHandle (см.Таблица 3)

Таблица 3 Функция DuplicateHandle

BOOL DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOption);

Параметры:

HANDLE hSourceProcessHandle. Описатель процесса, откуда берѐтся описатель объекта ядра.

HANDLE hSourceHandle. Описатель объекта для дублирования.

HANDLE hTargetProcessHandle. Описатель процесса, куда будет добавлена копия описателя объекта ядра.

LPHANDLE lpTargetHandle. Указатель на переменную, куда будет возвращѐн новый описатель объекта ядра.

DWORD dwDesiredAccess. Флаги доступа к копии описателя объекта ядра. Набор флагов зависит от типа дублируемого объекта ядра.

BOOL bInheritHandle. Определяет, может ли описатель наследоваться дочерними процессами.

DWORD dwOption. Опции дублирования:

12

DUPLICATE_CLOSE_SOURCE – закрыть исходный описатель после дублирования.

DUPLICATE_SAME_ACCESS – дублировать флаги доступа к объекту,

игнорируя флаг dwDesiredAccess.

Возвращаемое значение. TRUE, если операция завершилась удачно.

Пример 2 Работа с описателями

// Общий алгоритм работы с описателями int _tmain(int argc, _TCHAR* argv[])

{

//В качестве примера создадим именованный объект ядра "мьютекс"

HANDLE hObject = CreateMutex(NULL, TRUE, _T("MyMutex"));

//После работы закроем описатель объекта

CloseHandle(hObject);

return 0;

}

// Разделение именованных объектов int _tmain(int argc, _TCHAR* argv[])

{

//В качестве примера создадим именованный объект ядра "мьютекс"

HANDLE hObject = CreateMutex(NULL, TRUE, _T("MyMutex"));

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

//пользователей увеличится на единицу.

HANDLE hDuplicate = CreateMutex(NULL, TRUE, _T("MyMutex"));

// После работы закроем описатель объекта

CloseHandle(hObject);

CloseHandle(hDuplicate);

return 0;

}

//Дублирование описателя функцией DuplicateHandle

//GetCurrentProcess() возвращает описатель текущего процесса.

#include <assert.h>

int _tmain(int argc, _TCHAR* argv[])

{

//В качестве примера создадим именованный объект ядра "мьютекс"

HANDLE hObject = CreateMutex(NULL, TRUE, _T("MyMutex")); HANDLE hDuplicate;

//Дублирование описателя объекта assert(DuplicateHandle(GetCurrentProcess(), hObject, GetCurrentProcess(), &hDuplicate, 0, FALSE, 0));

//После работы закроем описатель объекта

CloseHandle(hObject);

13

CloseHandle(hDuplicate);

return 0;

}

Задачи и упражнения

1.В справочной системе, поставляемой с Win32 SDK, найдите группы функций

a.управления объектами и описателями (Handles and Objects)

b.управления процессами и потоками (Process and Thread)

c.управление синхронизацией (Synchronization Functions)

d.управления файлами (File Functions)

e.управление памятью (Memory Management Functions)

2.Создайте консольное приложение в среде программирования. Заставьте работать программы из (

3.Пример 2 Работа с описателями)

4.Когда узнаете, как работать с объектом ядра «процесс» выполните следующее задание. Напишите программу, которая запускает дочерний процесс. Задача дочернего процесса прервать жизнь своего родителя.

Найдите как можно больше способов решения этой задачи.

5.Когда узнаете, как работать с синхронизирующими объектами ядра выполните следующее задание. Представьте, что в фундаментальной задаче Дейкстры «обедающие философы» каждый философ реализован отдельным потоком в собственном процессе. Соответственно N

философов потребуют синхронизации потоков в N процессах. Решите задачу с использованием разделения синхронизирующих объектов между процессами.

Контрольные вопросы

1.Что такое Win32 API. Что значит в названии цифра «32»? Какие ещѐ

API операционных систем вам известны? Какие из них стандартизованы?

14

2.Что такое защищѐнная подсистема в Windows NT? Какие защищѐнные подсистемы в ней реализованы?

3.О чѐм следует помнить при написании приложения для разных платформ Windows (Windows 95 и Windows NT, например)?

4.Что такое Win32 SDK? В чѐм отличие Win32 API от Win32 SDK?

5.Зачем в Win32 SDK введены собственные типы данных? Чем плохи в использовании стандартные типы C/C++?

6.Что такое объект ядра? Какой компонент ОС отвечает за управление объектами?

7.Перечислите известные вам объекты ядра.

8.Почему система предотвращает прямой доступ к объекту ядра из режима пользователя? Как можно получить прямой доступ?

9.Что такое описатель объекта ядра? Что такое таблица описателей?

10.Можно ли использовать один описатель объекта ядра в двух разных процессах?

11.Как происходит закрытие объекта ядра?

12.Какие способы разделения объектов ядра между процессами вам известны?

15

Лабораторная работа №2. Процессы в Windows API.

Цель занятия

ознакомиться с объектом ядра «процесс».

научиться

-создавать и управлять объектом ядра «процесс»;

-получать информацию о процессе.

Теория

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

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

закрытое виртуальное адресное пространство – диапазон адресов виртуальной памяти, которым может пользоваться процесс;

исполняемую программу – начальный код и данные, проецируемые на виртуальное адресное пространство процесса;

список открытых описателей различных системных ресурсов – семафоров, коммуникационных портов, файлов и других объектов, доступных всем потокам в данном процессе (см.

Рисунок 2);

контекст защиты, называемый маркером доступа (Access Token) и

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

сопоставленные с процессом;

уникальный идентификатор процесса (PID) (во внутрисистемной терминологии называемый идентификатором клиента);

минимум один поток.

16

Маркер

Объект

VAD

VAD

VAD

“процесс”

 

 

 

Дескрипторы виртуальных адресов (VAD) Таблица описателей

Поток

Поток

Поток

Рисунок 2. Процесс и его ресурсы (Windows 2000).

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

Дескрипторы виртуальных адресов (Virtual Address Descriptors, VAD) –

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

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

принадлежащих процессу. Чем выше класс приоритета, тем больше процессорного времени будет отведено потокам процесса. Классы приоритета в порядке возрастания как они определены в Windows API:

17

Таблица 4. Классы приоритетов процесса.

Числовое значение

Базовый

Константа, определѐнная в

приоритет

класса приоритета

winbase.h

(Pp)

 

 

 

 

 

0x40

4

IDLE_PRIORITY_CLASS

 

 

 

0x4000

6

BELOW_NORMAL_PRIORITY_

 

 

CLASS

 

 

 

0x20

8

NORMAL_PRIORITY_CLASS

 

 

 

0x8000

10

ABOVE_NORMAL_PRIORITY_C

 

 

LASS

 

 

 

0x80

13

HIGH_PRIORITY_CLASS

 

 

 

0x100

24

REALTIME_PRIORITY_CLASS

 

 

 

Каждому процессу при создании система отводит некоторый объѐм оперативной памяти (ОП) и увеличивает этот объѐм по мере необходимости до максимального (вычисленного системой) значения. Этот объѐм ОП называется рабочим множеством процесса.

Создание процессов.

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

Пример 3. Создание нового процесса.

void main()

{

STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(si)); si.cb=sizeof(si);

if (CreateProcess(―c:\\windows\\calc.exe‖, NULL,

NULL, NULL, FALSE,

18

NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))

{

CloseHandle(pi.hThread);

CloseHandle(pi.hProcess);

}

}

Завершение процессов

Процесс может завершить себя вызовом функции ExitProcess, что

является предпочтительным.

Для аварийного завершения другого процесса используйте функцию

TerminateProcess.

Пример 4. Два варианта завершения текущего процесса.

void main (void)

{

ExitProcess(0);

}

void main(void)

{

TerminateProcess(GetCurrentProcess(), 0xFF);

}

Задачи и упражнения

1.Написать программу, выводящую на экран командную строку процесса,

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

HIGH_PRIORITY_CLASS. Сменить текущий каталог процесса на

19

заданный пользователем (путѐм ввода имени каталога с клавиатуры).

Завершить программу с кодом возврата 0хFF.

2.Написать программу, создающую новый процесс c нормальным классом приоритета (REALTIME_PRIORITY_CLASS). Имя программы передаѐтся через командную строку. Получить его класс приоритета. Если класс приоритета не равен REALTIME_PRIORITY_CLASS, установить класс приоритета NORMAL_PRIORITY_CLASS. Дождаться окончания выполнения процесса и вывести на экран код завершения процесса.

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

4.Примечание: попробуйте создать процесс и задать класс приоритета реального времени (REALTIME_PRIORITY_CLASS). Посмотрите с каким классом приоритета на самом деле создался процесс. Объясните причину произошедшего.

5.Модифицируйте программу, что бы она завершала процесс с заданным

(например, с клавиатуры) идентификатором (PID).

6.Создайте класс С++, инкапсулирующий работу с процессами и выполняющий следующие функции:

создание процесса;

завершение процесса;

получение информации об идентификаторе процесса;

получение кода завершения процесса;

получение и установка класса приоритета процесса;

получение информации об операциях ввода-вывода, выполненных процессом;

получение информации о времени работы в режиме пользователя/ядра;

получение и изменение рабочего набора процесса;

20