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

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

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

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

1.Поясните употребление терминов «программа», «процесс», «задача», «поток», «нить».

2.Дайте понятие объекта ядра? Посредством чего обеспечивается доступ к объектам ядра из пользовательских программ?

3.Может ли процесс в мультипрограммном режиме выполняться быстрее,

чем в монопольном?

4.Что такое класс приоритета процесса? На что он влияет?

5.Что определяет маркер доступа (Access Token)?

6.Как вы считаете: может ли прикладной процесс изменять маркер доступа

(Access Token), принадлежащий ему?

7.Известно, что программа А выполняется в монопольном режиме за 10

минут, а программа В – за 20 минут, то есть при последовательном выполнении они требуют 30 минут. Если Т – время выполнения обеих этих задач в режиме мультипрограммирования, то какое из неравенств,

приведенных ниже, справедливо?

a.Т<10

b.10<Т<20

c.20<Т<30

d.Т>30

8.Что такое «рабочее множество»? Что позволяет разрешить реализация этого понятия.

9.Изобразите диаграмму состояний процесса, поясните все возможные

переходы из одного состояния в другое.

10.Для чего каждая задача получает соответствующий дескриптор? Какие поля, как правило, содержатся в дескрипторе процесса (задачи)? Что такое контекст задачи.

11.Может ли существовать процесс без потоков?

21

12.Объясните понятие ресурса. Почему понятие ресурса является одним из фундаментальных при рассмотрении ОС? Какие виды и типы ресурсов вы знаете?

13.Что такое дескриптор виртуального адреса (VAD)? Что позволяет разрешить использование VAD?

14.Как вы считаете: сколько и каких списков дескрипторов задач может быть в системе? От чего должно зависеть это число?

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

16.Какие задачи возлагаются на интерфейс прикладного программирования

(API).

22

Лабораторная работа №3. Потоки в Windows API

Цель занятия

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

научиться

-создавать новые потоки в процессе;

-использовать функции ожидания освобождения объектов ядра;

-определять и устанавливать приоритет потока;

-приостанавливать и возобновлять работу потока;

-получать и изменять контекст потока;

-завершать поток.

Теория

Поток (Thread) – объект ядра, отвечающий за выполнение программного кода в процессе. При инициализации процесса система создаѐт и его первичный поток. Первичный поток начинает своѐ выполнение с функции main (в консольных приложениях) или с WinMain (GUI-

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

На уровне ОС поток представляется блоком потока с информационными структурами:

идентификатор потока TID (Thread ID)

стартовый адрес потока

данные о стеках потока:

23

o пользовательского режима;

oрежима ядра;

информация о контексте потока

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

время создания/завершения

информация о локальной памяти потока (TLS)

Диспетчеризация потоков

Диспетчеризация (управление выполнением) потоков выполняется в соответствии с их приоритетами. В Windows NT предусмотрено 32 уровня приоритета – от 0 до 31. Эти значения группируются так:

шестнадцать уровней реального времени (16–31);

пятнадцать варьируемых (динамических) уровней (1–15);

один системный уровень (0), зарезервированный для потока обнуления страниц (Zero page thread).

Приоритет каждого потока в Windows АРI устанавливается, исходя из класса приоритета его процесса и относительного приоритета самого потока.

Для относительного приоритета потока в Windows API определены константы (см. Таблица 5):

Таблица 5.Относительные приоритеты потока.

Числовое значение приоритета потока

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

winbase.h

 

 

 

THREAD_PRIORITY_IDLE

-15

 

 

THREAD_PRIORITY_LOWEST

-2

 

 

THREAD_PRIORITY_BELOW_NORMAL

-1

 

 

THREAD_PRIORITY_NORMAL

0

 

 

THREAD_PRIORITY_ABOVE_NORMAL

1

 

 

THREAD_PRIORITY_HIGHEST

2

 

 

THREAD_PRIORITY_TIME_CRITICAL

15

 

 

24

 

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

однако имеет возможность его изменить (функция SetThreadPriority).

Формула 1. Базовый приоритет потока.

Ptb = Pp+Pt

Пример 5. Расчѐт базового приоритета потока.

 

 

 

Pp=Pp(HIGH_PRIORITY_CLASS)

Ptb = Pp+Pt;

Pt=THREAD_PRIORITY_BELOW_NORMAL

Ptb = 13-1 = 12;

 

Ответ: Ptb = 12;

Ptb = ?

 

 

 

Дианамическое изменение приоритетов и текущий приоритет потока

Для потоков с базовым приоритетом Ptb=[1;15] - динамического диапазона, операционная система может самостоятельно изменить приоритет в одном из пяти случаев (см. Рисунок 3):

после завершения операции ввода-вывода;

по окончании операции ожидания на объекте исполнительной системы или на семафоре;

по окончании операции ожидания потоками активного процесса;

при пробуждении GUI-потоков из-за операции с окнами;

поток в состоянии готовности долго не получает процессор.

25

Рисунок 3 Динамическое изменение приоритетов потока.

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

Создание потоков

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

CreateThread. Каждый поток начинает своѐ выполнение с заданной функции и заканчивает при возврате из подпрограммы или при вызове функции

ExitThread либо TerminateThread.

Пример 6. Программа создаѐт два потока, печатающих на экране символы «*» и «!».

#include <iostream>

#include <windows.h>

//Функция, исполняемоя потоками.

//Выводит заданный параметром p символ

DWORD __stdcall CharsThread(LPVOID p)

26

{

// LPVOID p есть указатель на символ

TCHAR c = *(TCHAR*)(p);

// Бесконечно выводим на экран символ while(1)

{

std::cout << c;

}

return 0;

}

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

{

//Описатели потоков

HANDLE hThreads[2]; TCHAR asterisk = '*'; TCHAR exclam = '!';

//Поток, печатающий '*'

hThreads[0] = CreateThread(NULL, 0, CharsThread, &asterisk, 0, NULL);

// Поток, печатающий '!'

hThreads[1] = CreateThread(NULL, 0, CharsThread, &exclam, 0, NULL);

//Время ожидания завершения потоков

#define TIMEOUT 2000

//Ждѐм завершения двух потоков TIMEOUT миллисекунд

WaitForMultipleObjects(2, hThreads, TRUE, TIMEOUT);

/* Закрываем описатели потоков. Сами потоки продолжают

работать до завершения процесса */

CloseHandle(hThreads[0]);

CloseHandle(hThreads[1]); return 0;

}

Завершение работы потока

Поток может завершиться:

при возврате из функции потока;

при вызове потоком функции ExitThread;

при вызове самим потоком либо другим потоком функции

TerminateThread;

при завершении процесса, которому принадлежит поток.

27

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

завершится за 5000 мс (5 секунд).

// Функция потока с бесконечным циклом

DWORD __stdcall Loop(LPVOID lpParam)

{

for(;;){}

return 0;

}

int main(int argc, char* argv[])

{

HANDLE hThread; // Описатель потока

// Запуск потока с бесконечным циклом

hThread = CreateThread(NULL, 0, Loop, NULL, 0,

NULL);

// Ждѐм окончания работы потока 5000 мс.

if ( WAIT_OBJECT_0 != WaitForSingleObject(hThreads,

5000))

{

// Прерывание потока с кодом возврата 0xFF TerminateThread(hThread, 0xFF);

}

// Закрываем описатель потока. (Не забываем!!!)

CloseHandle(hThread);

return 0;

}

28

Приостановка и возобновление выполнения потока

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

(не приостановленный) поток. Для возобновления работы потока используется функция ResumeThread.

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

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

// Функция потока с бесконечным циклом

DWORD __stdcall Loop(LPVOID lpParam)

{

for(;;){}

return 0; }

int main(int argc, char* argv[])

{

HANDLE hThread; // Описатель потока

// Запуск потока с бесконечным циклом

hThread = CreateThread(NULL, 0, Loop, NULL, 0,

NULL);

// Вывод меню

cout << нажмите s для приостановки работы потока

<<endl;

cout << ―нажмите r для возобновления работы потока

<<endl;

cout << ―нажмите t для остановки потока и выхода из

программы‖ << endl;

29

char KeyPressed = ‗\0‘; while (KeyPressed != ‗t‘)

{

cin >> KeyPressed; switch (KeyPressed)

{

case ‗s‘: SuspendThread(hThread); break; case ‗r‘: ResumeThread(hThread);break;

}

}

// Прерываем поток

TerminateThread(hThread);

//Закрываем описатель потока. (Не забываем!!!)

CloseHandle(hThread);

return 0;

}

Контекст потока

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

CONTEXT. Для архитектуры Intel x86 структура представлена в приложении.

Для получения контекста потока используется функция

GetThreadContext с прототипом:

BOOL GetThreadContext(HANDLE hThread, LPCONTEXT

lpContext);

hThread – описатель потока для получения контекста.

30